使用C#创建包含多个文件的Zip存档

3
我的方法接收一个列表并创建ZIP文件和日志文件。它适用于较小数量的文件。但是当我处理大量文件时(已经测试了11,000个文件),它会抛出SystemOutOfMemory异常。
通过研究,我发现我的方法可能会在内存中增加很多负载。因此,我在代码中添加了刷新StreamWriter和Zip Archive的部分。我可能需要对文件流进行一些操作。
那么,如何解决这个问题的高效方法呢?
下面是代码:
        public static void BackupFilesToZip(string directory, string fileFilter, string zipFilePath, bool backupInSubDir, string logFilePath, List<FileInfo> filesToBackup)
    {
        FileInfo logFile = new FileInfo(logFilePath);
        FileInfo zipFile = new FileInfo(zipFilePath);
        int numberOfFiles = filesToBackup.Count;

        if (!Directory.Exists(zipFile.DirectoryName)) Directory.CreateDirectory(zipFile.DirectoryName);

        using (FileStream zipToOpen = new FileStream(zipFile.FullName, FileMode.OpenOrCreate))
        {
            using (ZipArchive archive = new ZipArchive(zipToOpen, ZipArchiveMode.Update))
            {
                ZipArchiveEntry readmeEntry = archive.CreateEntry(logFile.Name);
                using (StreamWriter writer = new StreamWriter(readmeEntry.Open()))
                {
                    writer.WriteLine("This ZIP archive was created: " + DateTime.Now.ToString("MM/dd/yy HH:mm:ss"));
                    writer.WriteLine("ZIP File: " + zipFilePath);
                    writer.WriteLine("Source Directory: " + directory);
                    string backupInSubText = "yes";
                    if (!backupInSubDir) backupInSubText = "no";
                    writer.WriteLine("Subdirectories included: " + backupInSubText);
                    writer.WriteLine("Filter Critera: " + fileFilter);
                    writer.WriteLine("Number of Files selected: " + numberOfFiles + " (for # of files archived/skipped scroll down)");
                    writer.WriteLine("");
                    writer.WriteLine("File Log:");

                    int filesArchivedCounter = 0;
                    int filesSkippedCounter = 0;
                    int filesSum = 0;

                    TaskbarManager.Instance.SetProgressState(TaskbarProgressBarState.Normal);

                    foreach (FileInfo file in filesToBackup)
                    {
                        //ZipArchiveEntry readmeEntry = archive.CreateEntry(logFile.Name);
                        string DateTimeStampBegin = DateTime.Now.ToString("MM/dd/yy HH:mm:ss");

                        try
                        {
                            string relativePath = MakeRelativePath(directory, file.FullName);
                            archive.CreateEntryFromFile(file.FullName, relativePath);
                            writer.WriteLine(DateTimeStampBegin + " - " + DateTime.Now.ToString("HH:mm:ss") + " archived: " + file.FullName);
                            filesArchivedCounter++;
                        }
                        catch
                        {
                            writer.WriteLine(DateTimeStampBegin + " - " + " SKIPPED: " + file.FullName);
                            filesSkippedCounter++;
                        }

                        filesSum = filesSkippedCounter + filesArchivedCounter;
                        TaskbarManager.Instance.SetProgressValue(filesSum, numberOfFiles);

                        //write from memory to files every 75 items (to avoid out of memory exception)
                        if (filesSum % 75 == 0)
                        {
                            writer.Flush();
                            zipToOpen.Flush();
                        }
                    }

                    writer.WriteLine("");
                    writer.WriteLine("# of Files archived: " + filesArchivedCounter);
                    writer.WriteLine("# of Files skipped: " + filesSkippedCounter);
                }

                if (!String.IsNullOrEmpty(logFile.Name))
                {
                    if (!Directory.Exists(logFile.DirectoryName)) Directory.CreateDirectory(logFile.DirectoryName);
                    readmeEntry.ExtractToFile(logFile.FullName, true);
                }

                TaskbarManager.Instance.SetProgressState(TaskbarProgressBarState.NoProgress); 
            }
        }
    }

此方法的所有字符串参数仅用于日志文件。


1
也许 https://msdn.microsoft.com/zh-cn/library/system.io.memorymappedfiles.memorymappedfile(v=vs.110).aspx(MemoryMappedFile)是一个开始的好地方,而不是使用 FileStream。 - Ron Beyer
我阅读了所有的MemoryMappedFile示例并尝试实现它。但是我无法让它正常工作。有人能提供一个代码示例,说明如何在这种上下文(ZipArchive)中使用MemoryMappedFile吗? - BillyVanilli
1个回答

0
你的实现问题在于将日志条目放在归档的开头,并在添加新文件后更新它,因此无法刷新zip。你应该将日志写入文件而不是归档,并在添加所有文件后再将其添加到归档中。

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