.NET 3.x OutOfMemoryException при получении большого количества файлов из каталога - C#
Формулировка задачи:
Доброго времени суток. Есть программа, которая в виде аргумента получает директорию, в которой она ищет и сравнивает все файлы и во всех поддиректориях. Проблема в том, что она слишком много жрет(30-40% ЦП и 400Мб ОЗУ, но так не всегда, это критические моменты). И если количество файлов уж очень большое(около 7к+) то вылетает выше написанное исключение. Могли бы вы подкинуть инфы об оптимизации кода на С#?
Решение задачи: «.NET 3.x OutOfMemoryException при получении большого количества файлов из каталога»
textual
Листинг программы
using System;
using System.Collections.Generic;
using System.IO;
namespace Compare
{
class myCompareFile
{
List<EqualFile> output = new List<EqualFile>();
List<File> AllFiles = new List<File>();
public List<EqualFile> CompareFile(string path)
{
// список файлов в этой директории
List<string> files = new List<string>();
// список папок в этой директории
List<string> dirs = new List<string>();
/*Шукаєм всі доступні файли*/
try
{
/*Добавляю знайдені папки і файли в список*/
files.AddRange(Directory.GetFiles(path));
dirs.AddRange(Directory.GetDirectories(path));
}
catch (UnauthorizedAccessException ex)
{
Console.WriteLine(ex.Message);
}
catch (DirectoryNotFoundException ex)
{
Console.WriteLine(ex.Message);
}
// перебираем все новые файлы
foreach (var newFile in files)
{
// получаем совпадения текущего файла с уже имеющимися в списке
List<string> fromAll = CompareLength(newFile);
if (fromAll.Count != 0) // если что-то там совпало...
foreach (var item2 in fromAll)
if (CompareHash(newFile, item2)) // то сравним хеши (ТС сравнит :)
output.Add(new EqualFile(newFile, item2)); // если совпали хеши, то добавим в совпадения
AllFiles.Add(new File(newFile, new FileInfo(newFile).Length)); // добавляем текущий файл ко всем
}
/*"Заглядаєм" за файлами в кожну директорію...*/
foreach (string dir in dirs)
{
// прогуливаемся по директориям дальше
CompareFile(dir);
}
return output;
}
/// <summary>
/// Сравнивает по длинне текущий файл с имеющимеся в списке
/// </summary>
/// <param name="file"></param>
/// <returns></returns>
private List<string> CompareLength(string file)
{
List<string> result = new List<string>();
foreach (var item in AllFiles)
if (item.Length == new FileInfo(file).Length)
result.Add(item.Path);
return result;
}
/// <summary>
/// Должна сравнивать файлы по хешу
/// </summary>
/// <param name="file1"></param>
/// <param name="file2"></param>
/// <returns>true если совпали</returns>
private bool CompareHash(string file1, string file2)
{
int sizeBlock = 16;
char[] buffer1 = new char[sizeBlock];
char[] buffer2 = new char[sizeBlock];
using (StreamReader sr1 = new StreamReader(file1), sr2 = new StreamReader(file2))
{
// предполагаю, если размеры файлов одинаковые,
// то нет смысла проверять на конец sr1 и sr2
long size = new FileInfo(file1).Length;
for (int i = 0; i < size; i += sizeBlock)
{
try
{
sr1.ReadBlock(buffer1, i, sizeBlock);
sr2.ReadBlock(buffer2, i, sizeBlock);
}
catch (Exception ex)
{
Console.WriteLine("Error: {0}", ex.Message);
}
// здесь должны сравниваться хеши, но это уже сделает автор :)
for (int j = 0; j < buffer1.Length; ++j)
if (buffer1[j] != buffer2[j])
return false;
if (size - i < sizeBlock)
sizeBlock = (int)(size - i);
}
}
return true;
}
}
/// <summary>
/// представляет класс файла.
/// </summary>
class File
{
public File() { }
public File(string path, long length)
{
Path = path;
Length = length;
}
public long Length { get; set; }
public string Path { get; set; }
public override string ToString()
{
return Path + "; Length = " + Length;
}
}
/// <summary>
/// класс для совпавших файлов
/// тупо для удобства, можно заменить
/// </summary>
public class EqualFile
{
public EqualFile() { }
public EqualFile(string file1, string file2)
{
File1 = file1;
File2 = file2;
}
public string File1 { get; set;}
public string File2 {get; set;}
public override string ToString()
{
return File1 + " ===== " + File2;
}
}
public class superMain
{
public static void Main()
{
myCompareFile mcf = new myCompareFile();
List<EqualFile> path = mcf.CompareFile("D:\\obraz\\");
foreach (var file in path)
Console.WriteLine(file);
Console.ReadLine();
}
}
}