[英]GzipStream blockwise compression results in a corrupted file
我正在尝试使用 GzipStream 类实现逐块压缩。 .NET Core 3.1、Visual Studio 2019、控制台应用程序。 我的操作系统是 Windows 10。我相信这应该是可能的,因为 gzip 文件按照格式规范由一个接一个的独立块组成。 但是我得到的结果文件已损坏。 这是代码:
using System;
using System.Globalization;
using System.IO;
using System.IO.Compression;
namespace GzipToMemoryStreamExample
{
class Program
{
private static int blockSize;
private static string sourceFileName = "e:\\SomeFolder\\SomeFile.ext";
private static byte[] currentBlock;
private static FileStream readingStream;
private static FileStream writingStream;
static void Main(string[] args)
{
Console.WriteLine("Enter block size:");
string blockSizeStr = Console.ReadLine();
int.TryParse(blockSizeStr, out blockSize);
readingStream = new FileStream(sourceFileName, FileMode.Open);
string resultingFileName = Path.ChangeExtension(sourceFileName, ".gz");
CreateAndOpenResultingFile(resultingFileName);
while (ReadBlock())
{
byte[] processedBlock = ProcessBlock(currentBlock);
writingStream.Write(processedBlock, 0, processedBlock.Length);
}
readingStream.Dispose();
writingStream.Dispose();
Console.WriteLine("Finished.");
Console.ReadKey();
}
private static bool ReadBlock()
{
bool result;
int bytesRead;
currentBlock = new byte[blockSize];
bytesRead = readingStream.Read(currentBlock, 0, blockSize);
result = bytesRead > 0;
return result;
}
private static byte[] ProcessBlock(byte[] sourceData)
{
byte[] result;
using (var outputStream = new MemoryStream())
{
using var compressionStream = new GZipStream(outputStream, CompressionMode.Compress);
compressionStream.Write(sourceData, 0, sourceData.Length);
result = outputStream.ToArray();
}
return result;
}
private static void CreateAndOpenResultingFile(string fileName)
{
if (File.Exists(fileName))
{
File.Delete(fileName);
}
writingStream = File.Create(fileName);
}
}
}
当我查看结果文件时,我发现结果在某种程度上取决于我选择的块大小。 如果它小于 ~100 Kb,则生成的“压缩”块每个大小为 10 字节,这会导致非常小的无用文件。 如果块的大小大于 ~100 Kb,则文件的大小会变得相当大,大约是原始大小的 80%,但仍然损坏。
我还检查了块标题,结果发现它们很奇怪。 OS 设置为 TOPS-20(0x0a 值),块末尾的 ISIZE 总是完全错误的。
我的错误是什么?
它只是通过移动result = outputStream.ToArray();解决的。 正如 Mark Adler 在评论中建议的那样,使用范围从compressionStream 中排除。
private static byte[] ProcessBlock(byte[] sourceData)
{
byte[] result;
using (var outputStream = new MemoryStream())
{
using (var compressionStream = new GZipStream(outputStream, CompressionMode.Compress))
{
compressionStream.Write(sourceData, 0, sourceData.Length);
}
result = outputStream.ToArray();
}
return result;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.