如何将大文件 (12gb) 拆分为多个 1GB 压缩 (.gz) 档案? C#

How to split big file(12gb) into multiple 1GB compressed(.gz) archives? C#

我有一个很大的 .bak 文件 - 将近 12GB。 我需要在代码中将它分成多个 2gb .gz 档案。

最大的问题是我需要稍后验证这个档案。

你知道,当你用 winrar 将一个文件拆分为 3 或 4 个档案时,然后你只需按下 "unpack" 它就会将它们全部解压到一个文件中,或者如果没有足够的档案则崩溃(你删除一个)。

我需要这样的东西。

public void Compress(DirectoryInfo directorySelected)
{
    int writeStat = 0;

    foreach (FileInfo fileToCompress in directorySelected.GetFiles())
    {
        using (FileStream originalFileStream = fileToCompress.OpenRead())
        {
            if ((File.GetAttributes(fileToCompress.FullName) &
               FileAttributes.Hidden) != FileAttributes.Hidden & fileToCompress.Extension != ".gz")
            {
                bytesToRead = new byte[originalFileStream.Length];
                int numBytesRead = bytesToRead.Length;

                while (_nowOffset < originalFileStream.Length)
                {                                
                    writeStat = originalFileStream.Read(bytesToRead, 0, homMuchRead);

                    using (FileStream compressedFileStream = File.Create(fileToCompress.FullName + counter + ".gz"))
                    {
                        using (GZipStream compressionStream = new GZipStream(compressedFileStream,
                           CompressionMode.Compress))
                        {
                            compressionStream.Write(bytesToRead, 0, writeStat);
                        }
                    }
                    _nowOffset = _nowOffset + writeStat;                        
                    counter++;
                }
                FileInfo info = new FileInfo(directoryPath + Path.DirectorySeparatorChar + fileToCompress.Name + ".gz");
                //Console.WriteLine($"Compressed {fileToCompress.Name} from {fileToCompress.Length.ToString()} to {info.Length.ToString()} bytes.");
            }
        }
    }
}

它运行良好,但我不知道如何验证它们的计数。

我在测试对象上有 7 个存档。但是如何在一个文件中读取它们,并验证该文件是否已满。

GZip 格式本身不支持您想要的。

Zip 有,该功能称为“跨区存档”,但 .NET 中的 ZipArchive class 没有。为此,您需要一个 third-party 库,例如 DotNetZip.

但有解决方法。

创建一个继承自Stream抽象的class,对外假装它是一个可以写入但不能读取或查找的单个流,在实现中写入多个部分,2GB /每个。在实现中使用 .NET 提供的 FileStream。在 class 的 long 字段中跟踪写入的总长度。一旦下一个 Write() 调用超过 2GB,写入刚好达到 2GB 的字节,关闭并处理底层 FileStream,打开另一个具有下一个文件名的文件,将文件长度计数器重置为 0,然后写入剩余的从缓冲区到 Write() 调用的字节数。重复直到关闭。

创建自定义流的实例,传递给 GZipStream 的构造函数,并将完整的 12GB 源数据复制到 GZipStream。

如果你做对了,输出的文件大小正好是 2GB(最后一个除外)。

要读取和解压缩它们,您需要使用自定义流实现类似的技巧。编写一个流 class 来动态连接多个文件,假装它是一个流,但这次你只需要实现 Read() 方法。将该连接流提供给框架中的 GZipStream。如果您重新订购或销毁某些部件,GZipStream 解压缩失败的可能性非常高(但不是 100%),抱怨 CRC 校验和。

P.S。要实施和调试上述 2 个流,我建议使用更小的数据集,例如12 MB 的数据,拆分为 1MB 的压缩块。一旦你让它工作,增加常量并用完整的 12GB 数据进行测试。