2010-09-23 10 views
10

Tengo un archivo de texto que quiero leer línea por línea y registro la posición en el archivo de texto a medida que avanzo. Después de leer cualquier línea del archivo, el programa puede salir, y debo reanudar la lectura del archivo en la siguiente línea cuando se reanude.¿Por qué FileStream.Position aumenta en múltiplos de 1024?

Aquí hay un código de ejemplo:

using (FileStream fileStream = new FileStream("Sample.txt", FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) 
{ 
    fileStream.Seek(GetLastPositionInFile(), SeekOrigin.Begin); 
    using (StreamReader streamReader = new StreamReader(fileStream)) 
    { 
     while (!streamReader.EndOfStream) 
     { 
      string line = streamReader.ReadLine(); 
      DoSomethingInteresting(line); 
      SaveLastPositionInFile(fileStream.Position); 

      if (CheckSomeCondition()) 
      { 
       break; 
      } 
     } 
    } 
} 

Cuando ejecuta este código, el valor de fileStream.Position no cambia después de leer cada línea, que sólo avanza después de leer un par de líneas. Cuando cambia, aumenta en múltiplos de 1024. Ahora supongo que hay algo de almacenamiento intermedio bajo las cubiertas, pero ¿cómo puedo registrar la posición exacta en el archivo?

+0

que tal vez equivocada, pero es posible que tenga que leer char/byte a la vez con el fin de utilizar su posición sin amortiguación. O use las sobrecargas que aceptan una matriz byte/char. Entonces puedes hacer el buffering exacto tú mismo ... – Nate

+0

Estoy de acuerdo con Nate. Si desea una posición precisa, tendrá que hacerlo usted mismo con las versiones char [] de Read & ReadBlock. Supongo que ReadLine lee en un bloque de 1024 caracteres y luego devuelve las subcadenas entre \ n \ r caracteres. –

Respuesta

10

No es FileStream responsable, es StreamReader. Está leyendo 1K a la vez por eficiencia.

Hacer un seguimiento de la posición efectiva de la corriente en lo que se refiere al StreamReader es complicado ... especialmente en lo que ReadLine descartará el final de línea, por lo que no se puede reconstruir con precisión los datos originales (que podría tener terminó con "\ n" o "\ r \ n"). Sería bueno si StreamReader expuesto algo que hacer esto más fácil (estoy bastante seguro de que podría hacerlo sin demasiada dificultad), pero no creo que haya nada en la API actual para ayudarle a :(

por cierto, sugeriría que en vez de utilizar EndOfStream, sigue leyendo hasta ReadLine vuelve nula se siente más simple para mí:.

string line; 
while ((line = reader.ReadLine()) != null) 
{ 
    // Process the line 
} 
+0

"Por la eficiencia" es correcto! ¡Mi implementación inicial de leer 1 byte a la vez directamente desde FileStream es terriblemente ineficiente! Creo que debería implementar mi propia solución de almacenamiento en búfer. –

2

Estoy de acuerdo con Stefan M., es probablemente el búfer que es causando que la Posición sea incorrecta. Si solo es la cantidad de caracteres que ha leído de los que desea realizar un seguimiento, le sugiero que lo haga usted mismo, como en:

 using(FileStream fileStream = new FileStream("Sample.txt", FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) { 
      fileStream.Seek(GetLastPositionInFile(), SeekOrigin.Begin); 
      **Int32 position = 0;** 
      using(StreamReader streamReader = new StreamReader(fileStream)) { 
       while(!streamReader.EndOfStream) { 
        string line = streamReader.ReadLine(); 
        **position += line.Length;** 
        DoSomethingInteresting(line); 
        **SaveLastPositionInFile(position);** 

        if(CheckSomeCondition()) { 
         break; 
        } 
       } 
      } 
     } 
+0

Esta es una gran sugerencia, pero no estoy seguro de que sea completamente viable dada esa línea. La longitud puede no ser la cantidad de bytes que se leyeron. Como mencionó Jon, StreamReader soltará caracteres como \ r y \ n. –

0

disponer que el archivo no es demasiado grande, ¿por qué no leer toda la cosa en grandes desconchados y luego manipular la cadena - probablemente más rápido que el stop and go de E/S.

Por ejemplo,

  //load entire file 
      StreamReader srFile = new StreamReader(strFileName); 
      StringBuilder sbFileContents = new StringBuilder(); 
      char[] acBuffer = new char[32768]; 
      while (srFile.ReadBlock(acBuffer, 0, acBuffer.Length) 
       > 0) 
      { 
       sbFileContents.Append(acBuffer); 
       acBuffer = new char[32768]; 
      } 

      srFile.Close(); 
Cuestiones relacionadas