Modifica una riga specifica di un file di testo in C #

Ho due file di testo, Source.txt e Target.txt. La sorgente non verrà mai modificata e contiene N righe di testo. Quindi, voglio eliminare una specifica riga di testo in Target.txt e sostituirla con una specifica riga di testo da Source.txt, so quale numero di linea ho bisogno, in realtà è il numero di riga 2, entrambi i file.

Non ho qualcosa del genere:

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

Ma quando apro il writer, il file di destinazione viene cancellato, scrive le righe, ma, quando viene aperto, il file di destinazione contiene solo le righe copiate, il resto viene perso.

Cosa posso fare?

Non è ansible riscrivere una riga senza riscrivere l’intero file (a meno che le righe non abbiano la stessa lunghezza). Se i tuoi file sono piccoli, allora leggendo l’intero file di destinazione in memoria e poi scrivendolo di nuovo potrebbe avere senso. Puoi farlo in questo modo:

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

Se i file sono grandi, sarebbe meglio creare un nuovo file in modo da poter leggere lo streaming da un file mentre si scrive all'altro. Ciò significa che non è necessario avere l'intero file in memoria in una volta. Puoi farlo in questo modo:

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

In seguito è ansible spostare il file una volta che si è sicuri che l'operazione di scrittura abbia avuto esito positivo (non sono stati lanciati eccipienti e lo scrittore è stato chiuso).

Nota che in entrambi i casi è un po 'di confusione che tu stia usando l'indicizzazione basata su 1 per i tuoi numeri di linea. Potrebbe avere più senso nel codice utilizzare l'indicizzazione basata su 0. È ansible avere un indice basato su 1 nell'interfaccia utente del programma, se lo si desidera, ma convertirlo in un indice 0 prima di inviarlo ulteriormente.

Inoltre, uno svantaggio di sovrascrivere direttamente il vecchio file con il nuovo file è che se fallisce a metà strada si rischia di perdere definitivamente qualsiasi dato non sia stato scritto. Scrivendo prima su un terzo file, si eliminano solo i dati originali dopo essersi assicurati di averne un'altra copia (corretta), in modo da poter recuperare i dati se il computer si blocca a metà.

Un'ultima osservazione: ho notato che i tuoi file avevano un'estensione xml. Potresti considerare se ha più senso usare un parser XML per modificare il contenuto dei file invece di sostituire linee specifiche.

il modo più semplice è:

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

utilizzo:

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

È necessario aprire il file di output per l’accesso in scrittura anziché utilizzare un nuovo StreamReader, che sovrascrive sempre il file di output.

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

Naturalmente, dovrai sempre cercare la riga corretta nel file di output, il che sarà difficile dal momento che non puoi leggere da esso, quindi a meno che tu non sappia già l’offset di byte da cercare, probabilmente vuoi veramente leggere / scrivere accesso.

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

con questo stream, puoi leggere finché non arrivi al punto in cui vuoi apportare delle modifiche, quindi scrivi. Tieni presente che stai scrivendo byte, non righe, quindi per sovrascrivere una riga dovrai scrivere lo stesso numero di caratteri della riga che desideri modificare.

Quando crei uno StreamWriter , crea sempre un file da zero, dovrai creare un terzo file e copiare dalla destinazione e sostituire quello che ti serve, e quindi sostituire quello vecchio. Ma come posso vedere quello che ti serve è la manipolazione XML, potresti voler usare XmlDocument e modificare il tuo file usando Xpath.

Immagino che il sotto dovrebbe funzionare (invece della parte dello scrittore dal tuo esempio). Sfortunatamente non ho un ambiente di costruzione, quindi è dalla memoria, ma spero che sia d’aiuto

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