我有一个foreach循环,可将目录中的文件添加到zip存档中。它可以运行一会儿,但是如果要放入一个存档的文件过多,则内存使用率会持续长时间升高,直到最终我收到SystemOutOfMemory异常并全部崩溃为止。这是脚本的相关代码段:
//there is a load of script before this, but the important declarations look like this :
public class MyFileInfo
{
public string FileName { get; set; }
public DateTime ReferenceDate { get; set; }
public string ArchiveLocation { get; set; }
public string ArchiveName { get; set; }
public string ArchiveBackupLocation { get; set; }
}
public class ArchiveFiles
{
public string Name { get; set; }
public HashSet<MyFileInfo> FileList { get; set; }
}
var distinctArchives = new Dictionary<string, MyTools.ArchiveFiles>();
//----------------------------------------------------
//-- The loop that is causing problems is below here--
//----------------------------------------------------
TotalFileCount = AllFilesToArchive.Count();
TotalArchiveCount = distinctArchives.Count();
CurrentFileCount = 0;
foreach (var archive in distinctArchives)
{
//reset the file count to zero before we start on this new archive. note that the currentfilecount is outside the loop and will not get reset.
FilesProcessedIntoThisArchive = 0;
TotalFilesInThisArchive = archive.Value.FileList.Count();
CurrentArchiveName = archive.Key;
string currentBackupName = archive.Value.Name;
//make folders for the archives to go in
if (!Directory.Exists(Path.GetDirectoryName(archive.Key)))
{
BasicTools.CreateFolderWithParentsAccess(Path.GetDirectoryName(archive.Key));
}
CreateEmptyArchive_atSource(CurrentArchiveName);
//HERE IS THE REAL PROBLEM The memory builds up within these "using" groups
using (FileStream zipToOpen = new FileStream(CurrentArchiveName, FileMode.Open))
{
using (ZipArchive archiveZip = new ZipArchive(zipToOpen, ZipArchiveMode.Update))
{
foreach (var file in archive.Value.FileList)
{
//if the user pressed abort on the progress dialog, then we need to stop this before we start any more files into the archive
if (bgWorker.CancellationPending)
{
break;
}
//we gotta set some of our values into properties for use of the progress bar
FilesProcessedIntoThisArchive++;
CurrentFileCount++;
CurrentFileName = file.FileName;
decimal progressAmount = (CurrentFileCount / TotalFileCount) * 100;
try
{
//so we already have the archive, we just need to add the file to the archive.
ZipArchiveEntry entry = archiveZip.CreateEntryFromFile(SourceDirectory + CurrentFileName, CurrentFileName, CompressionLevel.Optimal);
}
catch (Exception ex)
{
MessageBox.Show("Problem adding the file to the archive: " + ex.Message);
continue;
}
//if we have been asked to delete the files, we better do it.
if (DeleteFiles)
{
File.Delete(SourceDirectory + @"\" + CurrentFileName);
}
//tell the user the latest news
bgWorker.ReportProgress((int)progressAmount);
}
}
}
}
FilesProcessedCount = (int)CurrentFileCount;
问题在于,foreach (var file in archive.Value.FileList)...
循环完成之前,不会分配该存档的内存-如果此循环有很多迭代,则内存使用量会变得太大。
我尝试交换嵌套,以使using (FileStream zipToOpen...
和using (ZipArchive...
位位于foreach循环内,这意味着内存在每次迭代后都被分配了,但是虽然解决了该问题,但仍可以提高性能太糟糕了,导致该应用无法使用。
理想情况下,我希望有一种方法可以将文件分为int batchSize
个计数组,并在每次批处理后清除存档的内存,但是我看不到如何从我要去的地方提取文件。在文件的foreach循环中,如果执行此操作...是否需要更改为使用while循环来执行此操作?。
我在网上找到的所有建议都表明我应该使用“使用”结构来分配内存,但是在这种情况下,这让我很沮丧-我需要一种中途的房子设置一定数量的foreach迭代,然后暂时退出“使用”结构,然后再跳回并继续foreach循环...我有些困惑。
您认为我应该怎么做?