2009-12-28 180 views
18

Tengo dos archivos de texto, Source.txt y Target.txt. La fuente nunca se modificará y contendrá N líneas de texto. Por lo tanto, quiero eliminar una línea de texto específica en Target.txt y reemplazarla por una línea específica de texto de Source.txt, sé qué número de línea necesito, en realidad es el número de línea 2, ambos archivos.Editar una línea específica de un archivo de texto en C#

no he algo como esto:

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

Pero cuando abro el escritor, el archivo de destino se borran, escribe las líneas, pero, cuando se abre, el archivo de destino sólo contiene las líneas copiadas, la el resto se pierde

¿Qué puedo hacer?

Respuesta

38

No puede volver a escribir una línea sin volver a escribir todo el archivo (a menos que las líneas tengan la misma longitud). Si sus archivos son pequeños, entonces leer todo el archivo objetivo en la memoria y luego escribirlo de nuevo puede tener sentido. Usted puede hacer que de esta manera:

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

Si los archivos son grandes sería mejor crear un nuevo archivo para que pueda leer el streaming de un archivo mientras se escribe en la otra. Esto significa que no necesita tener todo el archivo en la memoria a la vez. Puede hacerlo de esta manera:

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

se puede mover después el archivo una vez que esté seguro de que la operación de escritura ha tenido éxito (sin excecption fue arrojado y el escritor está cerrado).

Tenga en cuenta que en ambos casos es un poco confuso que utilice la indexación basada en 1 para sus números de línea. Puede tener más sentido en su código usar la indexación basada en 0. Si lo desea, puede tener un índice basado en 1 en su interfaz de usuario para su programa, pero conviértalo a un índice 0 antes de enviarlo más.

Además, una desventaja de sobrescribir directamente el archivo anterior con el nuevo archivo es que si falla a la mitad, puede perder permanentemente los datos que no se escribieron. Al escribir primero en un tercer archivo, usted solo borra los datos originales después de estar seguro de que tiene otra copia (corregida), de modo que puede recuperar los datos si la computadora se bloquea a la mitad.

Una observación final: noté que sus archivos tenían una extensión xml. Es posible que desee considerar si tiene más sentido utilizar un analizador XML para modificar el contenido de los archivos en lugar de reemplazar líneas específicas.

2

Cuando crea un archivo StreamWriter siempre crea un archivo desde cero, tendrá que crear un tercer archivo y copiarlo del objetivo y reemplazar lo que necesita, y luego reemplazar el anterior. Pero como puedo ver lo que necesita es manipulación XML, puede usar XmlDocument y modificar su archivo usando Xpath.

1

Supongo que lo siguiente debería funcionar (en lugar de la parte del escritor de su ejemplo). Estoy por desgracia sin entorno de construcción por lo que es de la memoria, pero espero que ayude

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

es necesario abrir el archivo de salida para acceso de escritura en lugar de utilizar un nuevo StreamReader, que siempre sobrescribe el archivo de salida.

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

Por supuesto, todavía tendrá que buscar a la línea correcta en el archivo de salida, que será difícil ya que no puede leer de él, por lo menos que ya conoce el desplazamiento de bytes a tratar de, probablemente quieras acceso de lectura/escritura.

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

con esta secuencia, puede leer hasta llegar al punto en el que desea realizar cambios y luego escribir. Tenga en cuenta que está escribiendo bytes, no líneas, por lo que para sobrescribir una línea necesitará escribir la misma cantidad de caracteres que la línea que desea cambiar.

21

la forma más fácil es:

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

uso:

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

respuesta Absolutamente genial !!!! ... totalmente a trabajar aquí. ejecutándose en dot net 2.0 ... en Unity3d es: ___ function lineChanger (newText: String, fileName: String, line_to_edit: int) { var arrLine: String [] = File.ReadAllLines (fileName); arrLine [line_to_edit - 1] = newText; File.WriteAllLines (fileName, arrLine); } –

+0

Esto tiene 1 problema, que reescribe todo el archivo. –

+0

esto también carga todo el archivo en la memoria de una vez. pero es probablemente el enfoque más fácil y todavía utilizable con archivos pequeños. –

Cuestiones relacionadas