2009-12-28 42 views
18

Ich habe zwei Textdateien, Source.txt und Target.txt. Die Quelle wird niemals geändert und enthält N Textzeilen. Also, ich möchte eine bestimmte Zeile von Text in Target.txt löschen, und durch eine bestimmte Zeile von Text aus Source.txt ersetzen, weiß ich, welche Nummer der Zeile ich brauche, ist eigentlich die Zeile Nummer 2, beide Dateien.Bearbeiten Sie eine bestimmte Zeile einer Textdatei in C#

I haven etwas wie folgt aus:

string line = string.Empty; 
int line_number = 1; 
int line_to_edit = 2; 

using (StreamReader reader = new StreamReader(@"C:\source.xml")) 
{ 
    using (StreamWriter writer = new StreamWriter(@"C:\target.xml")) 
    { 
     while ((line = reader.ReadLine()) != null) 
     { 
      if (line_number == line_to_edit) 
      { 
       writer.WriteLine(line); 
      } 

      line_number++; 
     } 
    } 
} 

Aber wenn ich die Writer öffnen, erhalten die Zieldatei gelöscht, schreibt es die Linien, aber, wenn es geöffnet ist, enthält die Zieldatei nur die kopierten Zeilen, die Ruhe geht verloren.

Was kann ich tun?

Antwort

38

Sie können eine Zeile nicht umschreiben, ohne die gesamte Datei neu zu schreiben (es sei denn, die Zeilen haben die gleiche Länge). Wenn Ihre Dateien klein sind, kann es sinnvoll sein, die gesamte Zieldatei im Speicher zu lesen und sie dann erneut zu schreiben. Sie können das tun, wie folgt:

using System; 
using System.IO; 

class Program 
{ 
    static void Main(string[] args) 
    { 
     int line_to_edit = 2; // Warning: 1-based indexing! 
     string sourceFile = "source.txt"; 
     string destinationFile = "target.txt"; 

     // Read the appropriate line from the file. 
     string lineToWrite = null; 
     using (StreamReader reader = new StreamReader(sourceFile)) 
     { 
      for (int i = 1; i <= line_to_edit; ++i) 
       lineToWrite = reader.ReadLine(); 
     } 

     if (lineToWrite == null) 
      throw new InvalidDataException("Line does not exist in " + sourceFile); 

     // Read the old file. 
     string[] lines = File.ReadAllLines(destinationFile); 

     // Write the new file over the old file. 
     using (StreamWriter writer = new StreamWriter(destinationFile)) 
     { 
      for (int currentLine = 1; currentLine <= lines.Length; ++currentLine) 
      { 
       if (currentLine == line_to_edit) 
       { 
        writer.WriteLine(lineToWrite); 
       } 
       else 
       { 
        writer.WriteLine(lines[currentLine - 1]); 
       } 
      } 
     } 
    } 
} 

Wenn Ihre Dateien groß sind, wäre es besser, eine neue Datei zu erstellen, so dass Sie aus einer Datei Streaming lesen können, während Sie auf den anderen schreiben. Dies bedeutet, dass Sie nicht die gesamte Datei gleichzeitig im Speicher haben müssen. Sie können das tun, wie folgt:

using System; 
using System.IO; 

class Program 
{ 
    static void Main(string[] args) 
    { 
     int line_to_edit = 2; 
     string sourceFile = "source.txt"; 
     string destinationFile = "target.txt"; 
     string tempFile = "target2.txt"; 

     // Read the appropriate line from the file. 
     string lineToWrite = null; 
     using (StreamReader reader = new StreamReader(sourceFile)) 
     { 
      for (int i = 1; i <= line_to_edit; ++i) 
       lineToWrite = reader.ReadLine(); 
     } 

     if (lineToWrite == null) 
      throw new InvalidDataException("Line does not exist in " + sourceFile); 

     // Read from the target file and write to a new file. 
     int line_number = 1; 
     string line = null; 
     using (StreamReader reader = new StreamReader(destinationFile)) 
     using (StreamWriter writer = new StreamWriter(tempFile)) 
     { 
      while ((line = reader.ReadLine()) != null) 
      { 
       if (line_number == line_to_edit) 
       { 
        writer.WriteLine(lineToWrite); 
       } 
       else 
       { 
        writer.WriteLine(line); 
       } 
       line_number++; 
      } 
     } 

     // TODO: Delete the old file and replace it with the new file here. 
    } 
} 

Sie können danach die Datei bewegen, wenn Sie sicher sind, dass der Schreibvorgang erfolgreich war (kein excecption geworfen wurde und der Autor ist geschlossen).

Beachten Sie, dass es in beiden Fällen etwas verwirrend ist, wenn Sie die 1-basierte Indizierung für Ihre Zeilennummern verwenden. Es könnte in Ihrem Code sinnvoller sein, 0-basierte Indexierung zu verwenden. Sie können einen 1-basierten Index in Ihrer Benutzerschnittstelle zu Ihrem Programm haben, wenn Sie möchten, aber vor der Weiterleitung in eine 0-indexierte konvertieren.

Ein Nachteil des direkten Überschreibens der alten Datei mit der neuen Datei ist auch, dass wenn Sie auf halbem Weg fehlschlagen, Sie permanent alle Daten verlieren könnten, die nicht geschrieben wurden. Wenn Sie zuerst in eine dritte Datei schreiben, löschen Sie erst die ursprünglichen Daten, nachdem Sie sicher sind, dass Sie eine weitere (korrigierte) Kopie davon haben. So können Sie die Daten wiederherstellen, wenn der Computer zur Hälfte abstürzt.

Eine letzte Bemerkung: Ich bemerkte, dass Ihre Dateien eine XML-Erweiterung hatten. Sie sollten überlegen, ob es sinnvoller ist, einen XML-Parser zu verwenden, um den Inhalt der Dateien zu ändern, anstatt bestimmte Zeilen zu ersetzen.

2

Wenn Sie eine StreamWriter erstellen es immer eine Datei von Grund auf neu erstellen, müssen Sie eine dritte Datei erstellen und kopieren von Ziel und ersetzen, was Sie brauchen, und ersetzen Sie dann die alte. Aber wie ich sehe, was Sie brauchen, ist XML-Manipulation, möchten Sie vielleicht XmlDocument verwenden und Ihre Datei mit Xpath ändern.

1

Ich denke, die unten sollte funktionieren (anstelle des Schreiber Teil aus Ihrem Beispiel). Ich bin leider ohne Build-Umgebung, so dass es aus dem Gedächtnis, aber ich hoffe, es

using (var fs = File.Open(filePath, FileMode.Open, FileAccess.ReadWrite))) 
     { 
      var destinationReader = StreamReader(fs); 
      var writer = StreamWriter(fs); 
      while ((line = reader.ReadLine()) != null) 
      { 
       if (line_number == line_to_edit) 
       { 
        writer.WriteLine(lineToWrite); 
       } 
       else 
       { 
        destinationReader .ReadLine(); 
       } 
       line_number++; 
      } 
     } 
2

hilft Sie müssen vielmehr die Ausgabedatei für den Schreibzugriff öffnen, als einen neuen Stream verwenden, die immer die Ausgabedatei überschrieben.

StreamWriter stm = null; 
fi = new FileInfo(@"C:\target.xml"); 
if (fi.Exists) 
    stm = fi.OpenWrite(); 

Natürlich, werden Sie noch auf die richtige Zeile in der Ausgabedatei suchen, die schwer sein werden, da man nicht von ihnen lesen kann, so, wenn Sie bereits der bis zu suchen Offsetbyte KNOW, Sie möchten wahrscheinlich wirklich Lese-/Schreibzugriff.

FileStream stm = fi.Open(FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None); 

Mit diesem Stream können Sie lesen, bis Sie an den Punkt kommen, wo Sie Änderungen vornehmen möchten, und dann schreiben. Denken Sie daran, dass Sie Bytes schreiben, keine Zeilen. Um also eine Zeile zu überschreiben, müssen Sie die gleiche Anzahl von Zeichen wie die Zeile schreiben, die Sie ändern möchten.

21

der einfachste Weg ist:

static void lineChanger(string newText, string fileName, int line_to_edit) 
{ 
    string[] arrLine = File.ReadAllLines(fileName); 
    arrLine[line_to_edit - 1] = newText; 
    File.WriteAllLines(fileName, arrLine); 
} 

Nutzung:

lineChanger("new content for this line" , "sample.text" , 34); 
+0

Absolutely Brilliant Antwort !!!! ... total, hier zu arbeiten. läuft in dot net 2.0 ... in Unity3d ist es: ___ function lineChanger (newText: String, Dateiname: String, line_to_edit: int) { var arrLine: Zeichenfolge [] = File.ReadAllLines (fileName); arrLine [line_to_edit - 1] = newText; File.WriteAllLines (Dateiname, ArrLine); } –

+0

Dies hat 1 Problem, dass es die gesamte Datei neu schreibt. –

+0

Dies lädt auch die gesamte Datei auf einmal in den Speicher. aber es ist wahrscheinlich der einfachste Ansatz und immer noch mit kleinen Dateien verwendbar. –

Verwandte Themen