在foreach循环中处理内存C#

时间:2018-07-17 16:05:38

标签: c# foreach dispose

我有一个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循环...我有些困惑。

您认为我应该怎么做?

0 个答案:

没有答案