2010-12-08 5 views
1

Я пытаюсь сделать это, сравнивая два больших текстовых файла и, если они совпадают, выписывает строку, у меня это написано, но это очень медленно. Я надеялся, что у вас, ребята, может быть лучшая идея. В приведенном ниже примере я сравниваю набрать [3] splitfound [0]Сравнивая содержимое двух огромных текстовых файлов быстро

 string[] collectionlist = File.ReadAllLines(@"C:\found.txt"); 
     string[] foundlist = File.ReadAllLines(@"C:\collection_export.txt"); 
     foreach (string found in foundlist) 
     { 
      string[] spltifound = found.Split('|'); 
      string matchfound = spltifound[0].Replace(".txt", ""); ; 
      foreach (string collect in collectionlist) 
      { 
       string[] splitcollect = collect.Split('\\'); 
       string matchcollect = splitcollect[3].Replace(".txt", ""); 
       if (matchcollect == matchfound) 
       { 
        end++; 
        long finaldest = (start - end); 
        Console.WriteLine(finaldest); 
        File.AppendAllText(@"C:\copy.txt", "copy \"" + collect + "\" \"C:\\OUT\\" + spltifound[1] + "\\" + spltifound[0] + ".txt\"\n"); 
        break; 
       } 



      } 

     } 

Извините за расплывчатости парней,

То, что я пытаюсь сделать, это просто сказать, существует ли содержимое из одного файла в другой выписывает строку (строка не важна, просто время, чтобы найти два сравнительных результата). collectionlist как это:
компании Apple | Farm

foundlist, как это
C: \ корова \ лошадь \ turtle.txt
C: \ корова \ свинью \ apple.txt

, что я делаю, беру яблоко из списка коллекции, и находим строку, содержащую яблоко в списке поиска. Затем выпишите основной пакетный пакет Windows. Извините за путаницу.

Ответ (Все кредит Slaks)

   string[] foundlist = File.ReadAllLines(@"C:\found.txt"); 
      var collection = File.ReadLines(@"C:\collection_export.txt") 
     .ToDictionary(s => s.Split('|')[0].Replace(".txt","")); 

     using (var writer = new StreamWriter(@"C:\Copy.txt")) 
     { 
      foreach (string found in foundlist) 
      { 
       string[] splitFound = found.Split('\\'); 
       string matchFound = Path.GetFileNameWithoutExtension(found); 

       string collectedLine; 
       if (collection.TryGetValue(matchFound,out collectedLine)) 
       { 
        string[] collectlinesplit = collectedLine.Split('|'); 
        end++; 
        long finaldest = (start - end); 
        Console.WriteLine(finaldest); 
        writer.WriteLine("copy \"" + found + "\" \"C:\\O\\" + collectlinesplit[1] + "\\" + collectlinesplit[0] + ".txt\""); 
       } 
      } 
     } 
+0

Ваш код, как представляется, будет делать гораздо больше, чем простое текстовое сравнение, и если они действительно были большие файлы, то `ReadAllLines` потерпит неудачу с OUT- ошибка памяти. Насколько велики файлы? Вы пейджинг? – 2010-12-08 14:10:18

+0

один составляет около 1 миллиона строк, а другой около 200k. – 2010-12-08 14:10:56

ответ

4
  • Вызов File.ReadLines() (.NET 4) вместо ReadAllLines() (.NET 2.0).
    ReadAllLines необходимо построить массив для хранения возвращаемого значения, которое может быть чрезвычайно медленным для больших файлов.
    Если вы не используете .Net 4.0, замените его StreamReader.

  • Построить Dictionary<string, string> с matchCollect с (один раз), затем цикл через foundList и проверьте, содержит ли HashSet matchFound.
    Это позволяет заменить O (п) внутренний контур с O (1) хэш проверки

  • используйте устройство StreamWriter вместо вызова AppendText

  • EDIT: Call Path.GetFileNameWithoutExtension и другие Path методы вместо ручного управления строками.

Например:

var collection = File.ReadLines(@"C:\found.txt") 
    .ToDictionary(s => s.Split('\\')[3].Replace(".txt", "")); 

using (var writer = new StreamWriter(@"C:\Copy.txt")) { 
    foreach (string found in foundlist) { 
     string splitFound = found.Split('|'); 
     string matchFound = Path.GetFileNameWithoutExtension(found) 

     string collectedLine; 
     if (collection.TryGetValue(matchFound, collectedLine)) { 
      end++; 
      long finaldest = (start - end); 
      Console.WriteLine(finaldest); 
      writer.WriteLine("copy \"" + collectedLine + "\" \"C:\\OUT\\" 
          + splitFound[1] + "\\" + spltifound[0] + ".txt\""); 
     } 
    } 
} 
1

Сначала я хотел бы предложить, нормализуя как файлы и положить один из них в наборе. Это позволяет быстро проверить, присутствует ли конкретная строка, и уменьшает сложность от O (n * n) до O (n).

Также не следует открывать и закрывать файл каждый раз, когда вы пишете строку:

File.AppendAllText(...); // This causes the file to be opened and closed. 

Открыть выходной файл один раз в начале операции, писать строки в ней, а затем закрыть его, когда все были написаны строки.

1

У вас есть декартовый продукт, поэтому имеет смысл индексировать одну сторону, а не выполнять исчерпывающий линейный поиск.

Извлеките ключи из одного файла и используйте структуру данных Set или SortedList для их хранения. Это значительно ускорит поиск. (Ваш общий алгоритм будет O (N Л.Г. Н) вместо O (N ** 2))

Смежные вопросы