ZipArchive中为来自URL的大文件抛出了“System.OutOfMemoryException”

时间:2016-06-15 19:17:20

标签: c# asp.net-mvc stream

我有一个包含zip文件的网址。需要从URL解压缩文件。 URL使用webclient打开并读取,然后添加到Stream。然后在ZipArchive对象中使用它,它将解压缩文件并将它们存储在D:\驱动器中。当文件大约400Mb时,我得到'System.OutOfMemoryException'

必须使用Stream,因为webClient.OpenRead(Uri Address)返回一个Stream。以及使用ZipArchive(Stream stream)。

enter image description here

如何停止收到此消息?

 string zipFileUrl = "https://www.dropbox.com/s/clersbjdcshpdy6/oversize_zip_test_0.zip?dl=0"
 string output_path = @"D:\";

 using (WebClient webClient = new WebClient())
 {

     using (Stream streamFile = webClient.OpenRead(zipFileUrl))
     {
          using (ZipArchive archive = new ZipArchive(streamFile))//ERROR HERE
          {                                 
              var entries = archive.Entries;
              //Loops thru each file in Zip and adds it to directory
              foreach (var entry in entries)
              {
                 if (entry.FullName != "/" && entry.Name != "")
                 {

                    string completeFileName = Path.Combine(output_path, entry.FullName);
                    string directory = Path.GetDirectoryName(completeFileName);

                     //If directory does not exist then we create it.
                     if (!Directory.Exists(directory))
                     {
                         Directory.CreateDirectory(directory);
                     }
                     //Extracts zip from URL to extract path, and overwrites if file exists. 
                     entry.ExtractToFile(completeFileName, true);                                                         
                }
             }
         }
    }

1 个答案:

答案 0 :(得分:4)

我认为here might be your problem来自ZipArchive.Init方法

private void Init(Stream stream, ZipArchiveMode mode, Boolean leaveOpen)
{
    Stream extraTempStream = null;

    try
    {
        _backingStream = null;

        //check stream against mode
        switch (mode)
        {
            case ZipArchiveMode.Create:
                // (SNIP)
            case ZipArchiveMode.Read:
                if (!stream.CanRead)
                    throw new ArgumentException(SR.ReadModeCapabilities);
                if (!stream.CanSeek)
                {
                    _backingStream = stream;
                    extraTempStream = stream = new MemoryStream();
                    _backingStream.CopyTo(stream);
                    stream.Seek(0, SeekOrigin.Begin);
                }
                break;
            case ZipArchiveMode.Update:
                // (SNIP)
            default:
                // (SNIP)
        }
     // (SNIP)
}

如果streamFile.CanSeek为false(从WebClient开始),它会将整个文件复制到内存中然后处理该文件。这就是耗尽所有内存的东西。

尝试查找处理Zip文件的第三方库,并且不需要支持搜索的流。如果不能,请先将文件复制到磁盘文件夹,并将FileStream传入FileOptions.DeleteOnClose选项,然后在关闭流之前在zip中使用该流。

string zipFileUrl = "https://www.dropbox.com/s/clersbjdcshpdy6/oversize_zip_test_0.zip?dl=0";
string output_path = @"D:\";

using (var tempFileStream = new FileStream(Path.GetTempFileName(), FileMode.Create, 
                                           FileAccess.ReadWrite, FileShare.None, 
                                           4096, FileOptions.DeleteOnClose))
{
    using (WebClient webClient = new WebClient())
    {
        using (Stream streamFile = webClient.OpenRead(zipFileUrl))
        {
            streamFile.CopyTo(tempFileStream);
        }
    }
    tempFileStream.Position = 0;
    using (ZipArchive archive = new ZipArchive(tempFileStream))
    {
        var entries = archive.Entries;
        //Loops thru each file in Zip and adds it to directory
        foreach (var entry in entries)
        {
            if (entry.FullName != "/" && entry.Name != "")
            {

                string completeFileName = Path.Combine(output_path, entry.FullName);
                string directory = Path.GetDirectoryName(completeFileName);

                //If directory does not exist then we create it.
                if (!Directory.Exists(directory))
                {
                    Directory.CreateDirectory(directory);
                }
                //Extracts zip from URL to extract path, and overwrites if file exists. 
                entry.ExtractToFile(completeFileName, true);
            }
        }
    }
}