简体   繁体   中英

Out of memory exception while updating zip

I am getting OutofMemoryException while trying to add files to a .zip file. I am using 32-bit architecture for building and running the application.

string[] filePaths = Directory.GetFiles(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + "\\capture\\capture");
System.IO.Compression.ZipArchive zip = ZipFile.Open(filePaths1[c], ZipArchiveMode.Update);

foreach (String filePath in filePaths)
{
    string nm = Path.GetFileName(filePath);
    zip.CreateEntryFromFile(filePath, "capture/" + nm, CompressionLevel.Optimal);
}

zip.Dispose();
zip = null;

I am unable to understand the reason behind it.

The exact reason depends on a variety of factors, but most likely you are simply just adding too much to the archive. Try using the ZipArchiveMode.Create option instead, which writes the archive directly to disk without caching it in memory.

If you are really trying to update an existing archive, you can still use ZipArchiveMode.Create . But it will require opening the existing archive, copying all of its contents to a new archive (using Create ), and then adding the new content.

Without a good, minimal , complete code example , it would not be possible to say for sure where the exception is coming from, never mind how to fix it.

EDIT:

Here is what I mean by "…opening the existing archive, copying all of its contents to a new archive (using Create ), and then adding the new content":

string[] filePaths = Directory.GetFiles(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + "\\capture\\capture");

using (ZipArchive zipFrom = ZipFile.Open(filePaths1[c], ZipArchiveMode.Read))
using (ZipArchive zipTo = ZipFile.Open(filePaths1[c] + ".tmp", ZipArchiveMode.Create))
{
    foreach (ZipArchiveEntry entryFrom in zipFrom.Entries)
    {
        ZipArchiveEntry entryTo = zipTo.CreateEntry(entryFrom.FullName);

        using (Stream streamFrom = entryFrom.Open())
        using (Stream streamTo = entryTo.Open())
        {
            streamFrom.CopyTo(streamTo);
        }
    }

    foreach (String filePath in filePaths)
    {
        string nm = Path.GetFileName(filePath);
        zipTo.CreateEntryFromFile(filePath, "capture/" + nm, CompressionLevel.Optimal);
    }
}

File.Delete(filePaths1[c]);
File.Move(filePaths1[c] + ".tmp", filePaths1[c]);

Or something like that. Lacking a good, minimal , complete code example, I just wrote the above in my browser. I didn't try to compile it, never mind test it. And you may want to adjust some specifics (eg the handling of the temp file). But hopefully you get the idea.

The reason is simple. OutOfMemoryException means memory is not enough for the execution.

Compression consumes a lot of memory. There is no guarantee that a change of logic can solve the problem. But you can consider different methods to alleviate it.

1. Since your main program must be 32-bit, you can consider starting another 64-bit process to do the compression (use System.Diagnostics.Process.Start ). After the 64-bit process finishes its job and exits, your 32-bit main program can continue. You can simply use a tool already installed on the system, or write a simple program yourself.

2. Another method is to dispose each time you add an entry. ZipArchive.Dispose saves the file. After each iteration, memory allocated for the ZipArchive can be freed.

foreach (String filePath in filePaths)
{
    System.IO.Compression.ZipArchive zip = ZipFile.Open(filePaths1[c], ZipArchiveMode.Update);
    string nm = Path.GetFileName(filePath);
    zip.CreateEntryFromFile(filePath, "capture/" + nm, CompressionLevel.Optimal);
    zip.Dispose();
}

This approach is not straightforward, and it might not be as effective as the first approach.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM