2010-12-08 8 views
1

was ich im Grunde versuche zu tun ist, zwei riesige Textdateien zu vergleichen und wenn sie übereinstimmen schreiben eine Zeichenfolge, ich habe dies geschrieben, aber es ist extrem langsam. Ich hatte gehofft, dass ihr vielleicht eine bessere Idee habt. Im folgenden Beispiel ich vergleiche sammeln [3] splitfound [0]den Inhalt von zwei riesigen Textdateien schnell zu vergleichen

 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; 
       } 



      } 

     } 

Sorry für die Unbestimmtheit Jungs,

Was ich versuche ist einfach zu tun, sagen, wenn der Inhalt von einer Datei in existiert ein anderer schreibt eine Zeichenkette aus (die Zeichenkette ist nicht wichtig, lediglich die Zeit, um die beiden Vergleiche zu finden). Sammelliste ist wie folgt:
Apfel | Farm

foundlist ist wie folgt
C: \ Kuh \ Pferd \ turtle.txt
C: \ Kuh \ Schwein \ apple.txt

was ich bin Dabei wird Apfel aus der Sammelliste genommen und die Zeile gefunden, die Apfel in der Foundlist enthält. Dann schreiben Sie eine grundlegende Windows-Kopie Batch-Datei. Entschuldigung für die Verwirrung.

Antwort (Alle Kredite zu 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

Ihres Code scheint es viel mehr als ein einfacher Textvergleich zu tun, und wenn diese wirklich große Dateien sind, dann 'ReadAllLines' scheitern würde mit einem out- von Speicherfehler. Wie groß sind die Dateien? Blättern Sie? –

+0

Eins ist ungefähr 1 Millionen Zeilen und das andere ist ungefähr 200k –

+0

Wenn die 2 Text-Dateien eine unterschiedliche Anzahl von Zeilen haben, dann werden sie nie identisch/übereinstimmen, werden sie? –

Antwort

4
  • Anruf File.ReadLines() (.NET 4) anstelle von ReadAllLines() (.NET 2.0).
    ReadAllLines muss ein Array erstellen, um den Rückgabewert zu halten, der für große Dateien extrem langsam sein kann.
    Wenn Sie .Net 4.0 nicht verwenden, ersetzen Sie es durch einen StreamReader.

  • Körperbau ein Dictionary<string, string> mit dem matchCollect s (einmal), dann wird die Schleife durch foundList und prüfen, ob die HashSet matchFound enthält.
    Dadurch können Sie die O (n) innere Schleife mit einem O (1) hash Scheck

  • Verwenden ein Stream anstelle des Aufrufs AppendText

  • EDIT ersetzen: Call Path.GetFileNameWithoutExtension und die anderen Path Methoden anstatt Strings manuell zu manipulieren.

Zum Beispiel:

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\""); 
     } 
    } 
} 
+0

+1; um die Frage richtig zu beantworten. – AMissico

+0

Danke, ich werde es versuchen, ich habe eine Bearbeitung, um zu klären, was ich meinte, aber ich denke, du bist 100% auf Ihre Antwort –

+0

es gibt mir Fehler Argument 2 muss mit dem "out" übergeben werden Stichwort \t bei String gesammeltLine; –

1

Zuerst würde ich beiden Dateien vorschlagen zu normalisieren und in einer Reihe von ihnen setzen. Dadurch können Sie schnell testen, ob eine bestimmte Zeile vorhanden ist, und die Komplexität von O (n * n) nach O (n) reduzieren.

Auch sollten Sie nicht öffnen und die Datei jedes Mal schließen, schreiben Sie eine Zeile:

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

Öffnen Sie die Ausgabedatei einmal zu Beginn der Operation, schreiben Zeilen hinzu, schließen Sie es dann, wenn alle Zeilen wurden geschrieben.

1

Sie haben ein kartesisches Produkt, daher ist es sinnvoll, eine Seite zu indizieren, anstatt eine eneantive lineare Suche durchzuführen.

Extrahieren Sie die Schlüssel aus einer Datei und verwenden Sie entweder eine Set- oder eine SortedList-Datenstruktur, um sie zu speichern. Dies wird die Suche viel schneller machen. (Ihr Gesamtalgorithmus wird O (N lg N) anstelle von O (N ** 2))

Verwandte Themen