1

我正在尝试将文件添加到 Zip 文件中,同时保留目录。只要我没有要压缩的 100 Mb 文件,下面的代码基本上就可以工作。如果我只是压缩一个包含 1 个大约 250 Mb 文件的目录(顺便说一句,在具有大量内存的系统上),我会得到一个 OutOfMemory 异常write.Write()

我已经修改了代码以分块读取,因为它在我读/写整个文件时第一次失败。不知道为什么还是失败?

    using (FileStream zipToOpen = new FileStream(cZipName, eFileMode)) 
        ZipArchiveEntry readmeEntry = archive.CreateEntry(cFileToBackup

);

    using (BinaryWriter writer = new BinaryWriter(readmeEntry.Open()))
    {
        FileStream fsData = null;                                                                // Load file into FileStream
        fsData = new FileStream(cFileFull, FileMode.Open, FileAccess.Read);
        {
            byte[] buffer = new byte[1024];
            int bytesRead = 0;
            while ((bytesRead = fsData.Read(buffer, 0, buffer.Length)) > 0)
            {
                 writer.Write(buffer,0,bytesRead); // here it fails
                 fsData.Flush(); // ->CHANGED  THIS TO writer.Flush() SOLVED IT - nearly..
            }
        }
        fsData.Close();
    }

编辑:Arkadiusz K 是对的,我在阅读器上使用了同花顺,而不是作者。更改后,该程序将 1 Gb 或更大的文件压缩到它首先停止在 100 Mb 的位置。但是,当我尝试压缩例如 6 Gb 文件时出现另一个异常 - 它停止于: System.IO.IOException is unhandled Stream is too long Source=mscorlib StackTrace: at System.IO.MemoryStream.Write(Byte[] buffer , Int32 偏移量, Int32 计数) (等)

有谁知道为什么它仍然失败?我会说代码现在应该一次正确地读取和写入 1 Kb?

4

2 回答 2

7

首先,我真的很想格式化您的代码并使其尽可能简洁:

var readmeEntry = archive.CreateEntry(cFileToBackup);
using (var fsData = new FileStream(cFileFull, FileMode.Open, FileAccess.Read))
using (var writer = new BinaryWriter(readmeEntry.Open()))
{
    var buffer = new byte[1024];
    int bytesRead;
    while ((bytesRead = fsData.Read(buffer, 0, buffer.Length)) > 0)
    {
         writer.Write(buffer, 0, bytesRead); // here it fails
         writer.Flush();
    }
}

现在,解释它失败的原因:

BinaryWriter 是一个流编写器。当它必须将数据写入流时,它通常以长度为前缀写入,并且:

长度前缀意味着此方法首先将使用 BinaryWriter 实例的当前编码编码的字符串的长度(以字节为单位)写入流。该值写为无符号整数。然后,此方法将那么多字节写入流。

为了写入文件,在您的情况下,数据首先写入 MemoryStream 。这里,MemoryStream 是后备存储流。请参考下图:

.NET 中的流

(图片取自: http: //kcshadow.net/wpdeveloper/sites/default/files/streamd3.png

因为,您的系统内存大约为 6-8GB,或者因为您的应用程序仅分配了这么多内存,所以当您尝试压缩 6GB 文件时,后备存储流会扩展到最大可能,然后抛出异常。

于 2015-09-15T01:54:36.453 回答
3

关于您的编辑:遇到了同样的问题。经过一番挖掘,我发现它zipFileEntry.Open()返回 a WrappedStream,它是底层流(在完成写入之前无法刷新的流)。

WrappedStream就是问题所在:它的最大长度约为 2GB。我找不到解决这个问题的方法,所以我最终完全使用了不同的压缩库。

于 2018-03-27T13:24:32.833 回答