2010-06-23 4 views
12

Tengo un gran archivo de texto, tamaño> 4 GB y quiero reemplazar algo de texto programáticamente. Sé el número de línea en el que tengo que reemplazar el texto, pero el problema es que no quiero copiar todo el texto (junto con la línea reemplazada) en un segundo archivo. Tengo que hacer esto dentro del archivo fuente. ¿Hay alguna manera de hacer esto en C#?Edición de un archivo de texto en su lugar a través de C#

El texto que debe reemplazarse es exactamente del mismo tamaño que el texto de origen (si esto ayuda).

Respuesta

12

Dado que el archivo es tan grande es posible que desee echar un vistazo a la compatibilidad con .NET 4.0 para memory mapped files. Básicamente, tendrá que mover el puntero de archivo/secuencia a la ubicación en el archivo, sobrescribir esa ubicación y luego vaciar el archivo en el disco. No necesitará cargar todo el archivo en la memoria.

Por ejemplo, sin utilizar archivos mapeados en memoria, lo siguiente sobrescribirá una parte de un archivo ascii. Args es el archivo de entrada, el índice de inicio basado en cero y el nuevo texto.

static void Main(string[] args) 
    { 
     string inputFilename = args[0]; 
     int startIndex = int.Parse(args[1]); 
     string newText = args[2]; 

     using (FileStream fs = new FileStream(inputFilename, FileMode.Open, FileAccess.Write)) 
     { 
      fs.Position = startIndex; 
      byte[] newTextBytes = Encoding.ASCII.GetBytes(newText); 
      fs.Write(newTextBytes, 0, newTextBytes.Length); 
     } 
    } 
+0

Estoy usando .NET 3.5. Entonces, me temo, esta podría no ser una opción. Gracias por tu sugerencia. – Aamir

+1

@Aamir: seek/write/flush se puede hacer con archivos E/S típicos; mapeo de memoria no es requerido. pero si desea utilizar la asignación de memoria en 3.5, no necesita ninguna biblioteca de objetos especial, puede llamar directamente a la interfaz de win dll nativa (CreateFileMapping/MapViewOfFile/etc), a través de System.Runtime.Interopservices y DLLImport. –

+0

Este proyecto de código realiza una asignación de memoria en .NET 3.5. Está usando arreglos, pero apuesto a que no será difícil traducirlos a archivos. http://www.codeproject.com/KB/recipes/MemoryMappedGenericArray.aspx –

5

A menos que el nuevo texto tenga exactamente el mismo tamaño que el anterior, tendrá que volver a escribir el archivo. No hay manera de evitarlo. Al menos puede hacer esto sin tener todo el archivo en la memoria.

+0

Joel, el nuevo texto ES exactamente del mismo tamaño. ¿Cuál es la manera de hacer esto en tal caso? – Aamir

+0

Abra una secuencia de archivos, busque el punto donde se inicia el texto y escriba el nuevo texto en la secuencia. –

0

Supongo que querrá usar la clase FileStream y buscar su posición, y colocar sus datos actualizados.

1

Hola He probado lo siguiente: funciona bien. Esto atiende a líneas de longitud variable separadas por Environment.NewLine. si tiene líneas de longitud fijadas, puede buscarlas inmediatamente. Para convertir bytes en cadena y viceversa, puede usar Codificación.

static byte[] ReadNextLine(FileStream fs) 
     { 
      byte[] nl = new byte[] {(byte) Environment.NewLine[0],(byte) Environment.NewLine[1] }; 
      List<byte> ll = new List<byte>(); 
      bool lineFound = false; 
      while (!lineFound) 
      { 
       byte b = (byte)fs.ReadByte(); 
       if ((int)b == -1) break; 
       ll.Add(b); 
       if (b == nl[0]){ 
        b = (byte)fs.ReadByte(); 
        ll.Add(b); 
        if (b == nl[1]) lineFound = true; 
       } 
      } 
      return ll.Count ==0?null: ll.ToArray(); 
     } 
     static void Main(string[] args) 
     { 

      using (FileStream fs = new FileStream(@"c:\70-528\junk.txt", FileMode.Open, FileAccess.ReadWrite)) 
      { 
       int replaceLine=1231; 
       byte[] b = null; 
       int lineCount=1; 
       while (lineCount<replaceLine && (b=ReadNextLine(fs))!=null) lineCount++;//Skip Lines 

       long seekPos = fs.Position; 
       b = ReadNextLine(fs); 
       fs.Seek(seekPos, 0); 
       string line=new string(b.Select(x=>(char)x).ToArray()); 
       line = line.Replace("Text1", "Text2"); 
       b=line.ToCharArray().Select(x=>(byte)x).ToArray(); 
       fs.Write(b, 0, b.Length); 

      } 

     } 
Cuestiones relacionadas