在C#中使用BinaryWriter将文件添加到zip文件时内存不足

Dic*_*ick 1 c# out-of-memory binarywriter

我试图将文件添加到Zip文件,保留目录.下面的代码基本上是工作的,只要我没有几个100 Mb的文件压缩.如果我只用一个大约250 Mb的文件压缩一个目录(在一个有足够内存BTW的系统上),我就会得到一个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();
    }
Run Code Online (Sandbox Code Playgroud)

编辑:Arkadiusz K是对的,我在阅读器上使用了同花顺,而不是作家.更改之后,程序将首先停止在100 Mb的1 Gb或更多文件.但是,当我尝试压缩例如6 Gb文件时,我得到另一个例外 - 它停止:System.IO.IOException未处理Stream太长 Source = mscorlib StackTrace:at System.IO.MemoryStream.Write(Byte [] buffer ,Int32偏移量,Int32计数)(等)

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

dis*_*ame 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();
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

Length-prefixed表示当使用BinaryWriter实例的当前编码对流进行编码时,此方法首先写入字符串的长度(以字节为单位).该值写为无符号整数.然后,此方法将许多字节写入流.

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

.NET中的Streams

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

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