2009-05-13 11 views
7

Tengo un archivo de texto que se está escribiendo como parte de un extracto de datos muy grande. La primera línea del archivo de texto es la cantidad de "cuentas" extraídas.¿Cuál es la MEJOR manera de reemplazar texto en un archivo usando C#/.NET?

Debido a la naturaleza de este extracto, ese número no se conoce hasta el final del proceso, pero el archivo puede ser grande (algunos cientos de megas).

¿Cuál es la MEJOR manera en C#/.NET para abrir un archivo (en este caso, un archivo de texto simple) y reemplazar los datos que están en la primera "línea" de texto?

NOTA IMPORTANTE: - No es necesario que reemplace una "cantidad fija de bytes" - eso sería fácil. El problema aquí es que los datos que deben insertarse en la parte superior del archivo son variables.

NOTA IMPORTANTE 2: - Algunas personas han preguntado/mencionado simplemente manteniendo los datos en la memoria y luego reemplazándolos ... sin embargo eso está completamente fuera de cuestión. La razón por la cual este proceso se está actualizando se debe al hecho de que a veces se bloquea cuando se cargan algunas gigas en la memoria.

+0

"##### \ r \ n (lo que significa que no hay relleno)" ¿estás seguro de que no puedes tener una Zero líder? –

Respuesta

4

Si puede, debe insertar un marcador de posición que sobrescriba al final con el número y espacios reales.

Si esa no es una opción, primero escriba sus datos en un archivo de caché. Cuando conozca el número real, cree el archivo de salida y anexe los datos del caché.

+0

Sí, la única forma de evitar escribir los datos dos veces. Si se basa en texto, no debería haber problema, solo reserve una cantidad decente de espacios primero. –

+0

Esto es lo que me gustaría * hacer (reservar un espacio en blanco) - el único problema es que el formato de archivo para el que estoy escribiendo requiere ##### \ r \ n exacto (lo que significa que no hay relleno). - Buena respuesta, sin embargo. –

+1

@Timothy: ¿permite los ceros a la izquierda? –

1

Si el archivo extraído tiene solo unos pocos cientos de megabytes, puede guardar fácilmente todo el texto en la memoria hasta que se complete la extracción. Luego, puede escribir su archivo de salida como la última operación, comenzando con el recuento de registros.

+3

"solo unos pocos cientos de megabytes" ??? En serio ? – Cerebrus

+1

Tengo solo 2 Gigs en mi máquina, la mayoría de los demás en nuestra oficina tienen entre 4 y 8. ¿Qué es 200MB? Tal vez el 10% de la memoria total ... –

+0

Y lo que sucede en un año cuando el archivo es "solo unos pocos gigabytes", ¿entonces lo mantendrás todo en la memoria también? –

2

No necesito para reemplazar un " cantidad fija de bytes"

¿Seguro? Si escribe un número grande en la primera línea del archivo (UInt32.MaxValue o UInt64.MaxValue), cuando encuentre el número real correcto, puede reemplazar ese número de bytes con el número correcto, pero se rellenó con ceros , por lo tanto, sigue siendo un número entero válido. p.

Replace 999999 - your "large number placeholder" 
With  000100 - the actual number of accounts 
+0

¡Solución inteligente! - Sin embargo, la especificación del archivo con la que estoy trabajando no lo aceptará ... muy bien pensado :) –

+0

¿Te importa que pregunte por qué no? –

+0

Es una especificación de archivo, no respondió mi pregunta: P –

3

BEST es muy subjetiva. Para cualquier archivo pequeño, puede abrir fácilmente todo el archivo en la memoria y reemplazar lo que desee mediante una cadena reemplazar y luego volver a escribir el archivo.

Incluso para archivos grandes, no sería tan difícil cargar en la memoria. En los días de múltiples gigas de memoria, consideraría que cientos de megabytes aún se pueden hacer fácilmente en la memoria.

¿Has probado este enfoque ingenuo? ¿Has visto un problema real con eso?

Si este es un archivo realmente grande (gigabytes en tamaño), consideraría escribir todos los datos primero en un archivo temporal y luego escribir el archivo correcto con la línea de encabezado entrando primero y luego añadiendo el resto del datos. Dado que sólo es texto, que probablemente solo un shell de DOS:

TYPE temp.txt >> outfile.txt 
2

parece que si entiendo bien la pregunta?

¿Cuál es la MEJOR manera en C#/.NET para abrir un archivo (en este caso, un archivo de texto simple) y reemplazar los datos que están en la primera "línea" de texto?

¿Qué le parece colocar en la parte superior del archivo un token {UserCount} cuando se crea por primera vez?

Luego use TextReader para leer el archivo línea por línea. Si es la primera línea, busque {UserCount} y reemplácela con su valor. Escribir cada línea que se lee en el uso de TextWriter

Ejemplo:

int lineNumber = 1; 
    int userCount = 1234; 
    string line = null; 

    using(TextReader tr = File.OpenText("OriginalFile")) 
    using(TextWriter tw = File.CreateText("ResultFile")) 
    { 

     while((line = tr.ReadLine()) != null) 
     { 
      if(lineNumber == 1) 
      { 
       line = line.Replace("{UserCount}", userCount.ToString()); 
      } 

      tw.WriteLine(line); 
      lineNumber++; 
     } 

    } 
+0

Esto es esencialmente lo que tenía que hacer, pero mi objetivo era * no * crear 2 archivos. –

+0

Tengo una solución más que he visto pero que aún no he verificado ni intentado. Básicamente, lo que debes hacer es usar algo como StreamWriter para escribir tu primer archivo y mantenerlo abierto.También escriba como sugerí el marcador de posición y guarde el punto inicial y final del token. Entonces, ahora que se encuentra al final del archivo, tiene el UserCount y solo necesita regresar y reemplazar el token con su valor. Para hacer eso, utilizas un BitStream al que creo que puedes acceder accediendo al StreamWriter.BaseStream y puedes escribir bytes en una ubicación específica en tu transmisión. Lo intentaré y lo probaré y publicaré. –

1

Ok, antes me sugirió un enfoque que sería una mejor si se trata de archivos existentes.

Sin embargo, en su situación, desea crear el archivo y durante el proceso de creación, vuelva al principio y escriba el recuento de usuarios. Esto hará exactamente eso.

Aquí hay una forma de hacerlo que evita tener que escribir el archivo temporal.

private void WriteUsers() 
    { 
     string userCountString = null; 
     ASCIIEncoding enc = new ASCIIEncoding(); 
     byte[] userCountBytes = null; 
     int userCounter = 0; 

     using(StreamWriter sw = File.CreateText("myfile.txt")) 
     { 
      // Write a blank line and return 
      // Note this line will later contain our user count. 
      sw.WriteLine(); 

      // Write out the records and keep track of the count 
      for(int i = 1; i < 100; i++) 
      { 
       sw.WriteLine("User" + i); 
       userCounter++; 
      } 

      // Get the base stream and set the position to 0 
      sw.BaseStream.Position = 0; 

      userCountString = "User Count: " + userCounter; 

      userCountBytes = enc.GetBytes(userCountString); 

      sw.BaseStream.Write(userCountBytes, 0, userCountBytes.Length); 
     } 

    } 
+0

Actualmente esa es la única respuesta que responde a la solicitud de edición de un archivo existente ... ¡Gracias! – ephraim

Cuestiones relacionadas