使用GZipStream将内存流保存为文件

5
我正在尝试使用Gzip压缩来压缩JSON文件以便发送到另一个位置。每天需要处理5000-10000个文件,我不需要在本地机器上保留压缩后的文件(它们实际上被传输到AWS S3进行长期存档)。
由于我不需要它们,我正在尝试将它们压缩到内存流中,然后使用该流来写入AWS,而不是将每个文件都压缩到磁盘上。但是每当我尝试这样做时,文件都会损坏(例如,当我在7-Zip中打开它们并尝试打开其中的JSON文件时,会显示“数据错误 文件已损坏”)。
当我尝试将内存流写入本地文件时,也会发生同样的事情,所以我现在正在解决这个问题。以下是代码:
string[] files = Directory.GetFiles(@"C:\JSON_Logs");

foreach(string file in files)
{
    FileInfo fileToCompress = new FileInfo(file);
    using (FileStream originalFileStream = fileToCompress.OpenRead())
    {
        using (MemoryStream compressedMemStream = new MemoryStream())
        {
            using (GZipStream compressionStream = new GZipStream(compressedMemStream, CompressionMode.Compress))
            {
                originalFileStream.CopyTo(compressionStream);
                compressedMemStream.Seek(0, SeekOrigin.Begin);
                FileStream compressedFileStream = File.Create(fileToCompress.FullName + ".gz");

                //Eventually this will be the AWS transfer, but that's not important here
                compressedMemStream.WriteTo(compressedFileStream); 
            }
        }
    }      
}

它已经生成了一个 .gz 文件。通常情况下,7-Zip 可以读取 .gz 文件。我尝试使用文件流替换内存流进行操作,结果运行良好。 - smullan
1个回答

6

重新排列using语句,以便在读取内存流内容时,GZipStream已经完成:

foreach(string file in files)
{
    FileInfo fileToCompress = new FileInfo(file);
    using (MemoryStream compressedMemStream = new MemoryStream())
    {
        using (FileStream originalFileStream = fileToCompress.OpenRead())
        using (GZipStream compressionStream = new GZipStream(
            compressedMemStream, 
            CompressionMode.Compress,
            leaveOpen: true))
        {
            originalFileStream.CopyTo(compressionStream);
        }
        compressedMemStream.Seek(0, SeekOrigin.Begin);

        FileStream compressedFileStream = File.Create(fileToCompress.FullName + ".gz");
        //Eventually this will be the AWS transfer, but that's not important here
        compressedMemStream.WriteTo(compressedFileStream); 
    }
}

释放流会处理其刷新和关闭。


没有注意到排列错误.. +1 - Jeroen van Langen
然后我在compressedMemStream.WriteTo(compressedFileStream);这一行收到了一个系统异常“无法访问已关闭的流”。 - smullan
@smullan:糟糕。GZipStream认为它拥有传递给它的流,这意味着它会在我们下面关闭MemoryStream。很不礼貌。我们通过传递leaveOpen参数来告诉它不要这样做。(我们也可以通过重新排列更多代码来修复此问题,因为MemoryStream可以通过其数组在关闭后进行读取,但我认为这更加优雅。) - Jeroen Mostert

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接