c# .net windows streaming filestream

Leer de un archivo en crecimiento en C#?



.net windows (4)

En C # / .NET (en Windows), ¿hay una manera de leer un archivo "en crecimiento" utilizando una secuencia de archivos? La longitud del archivo será muy pequeña cuando se abra el flujo de archivos, pero otro hilo escribirá en el archivo. Si / cuando el flujo de archivos se "pone al día" con el otro hilo (es decir, cuando Read() devuelve 0 bytes de lectura), quiero hacer una pausa para permitir que el archivo se almacene un poco, luego continuar leyendo.

Realmente no quiero usar un FilesystemWatcher y seguir creando nuevas secuencias de archivos (como se sugirió para los archivos de registro), ya que este no es un archivo de registro (es un archivo de video que se codifica sobre la marcha) y el rendimiento es un problema.

Gracias,
Robert


Esto funcionó con un StreamReader alrededor de un archivo, con los siguientes pasos:

  1. En el programa que escribe en el archivo, ábralo con lectura compartida, como esto:

    var out = new StreamWriter(File.Open("logFile.txt", FileMode.OpenOrCreate, FileAccess.Write, FileShare.Read));

  2. En el programa que lee el archivo, ábralo con el uso compartido de lectura-escritura, como este:

    using (FileStream fileStream = File.Open("logFile.txt", FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) using ( var file = new StreamReader(fileStream))

  3. Antes de acceder al flujo de entrada, compruebe si se ha llegado al final y, si es así, espere un momento.

    while (file.EndOfStream) { Thread.Sleep(5); }


La forma en que resolví esto es mediante la clase DirectoryWatcher / FilesystemWatcher, y cuando se dispara en el archivo que deseas, abres un FileStream y lo lees hasta el final. Y cuando termine de leer, guardo la posición del lector, de modo que la próxima vez que DirectoryWatcher / FilesystemWatcher se active, abra una secuencia y establezca la posición donde estaba la última vez.

La llamada a FileStream.length actualmente es muy lenta, no he tenido problemas de rendimiento con mi solución (estaba leyendo un "registro" de 10 MB a 50 ISH).

Para mí, la solución que describo es muy simple y fácil de mantener, la probaría y la perfilaría. No creo que vayas a tener ningún problema de rendimiento basado en ello. Hago esto cuando las personas están jugando un juego de múltiples hilos, tomando todo su CPU y nadie se ha quejado de que mi analizador es más exigente que los analizadores de la competencia.


Otra cosa que podría ser útil es que la clase FileStream tiene una propiedad llamada ReadTimeOut que se define como:

Obtiene o establece un valor, en milisegundos, que determina cuánto tiempo intentará leer la secuencia antes de que se agote el tiempo de espera. (heredado de Stream)

Esto podría ser útil ya que cuando sus lecturas se pongan al día con sus escrituras, el hilo que realiza las lecturas puede pausarse mientras el búfer de escritura se vacía Ciertamente, valdría la pena escribir una pequeña prueba para ver si esta propiedad ayudaría a su causa de alguna manera.

¿Las operaciones de lectura y escritura ocurren en el mismo objeto? Si es así, puede escribir sus propias abstracciones sobre el archivo y luego escribir el código de comunicación entre hilos de manera tal que el hilo que está realizando las escrituras y notifique al hilo que realiza las lecturas cuando se hace para que el hilo que realiza las lecturas sepa cuándo parar de leer. cuando llega a EOF.


Puede hacer esto, pero debe realizar un seguimiento cuidadoso de las posiciones de lectura y escritura del archivo utilizando Stream.Seek y con la sincronización adecuada entre los subprocesos. Normalmente, usaría un EventWaitHandle o una subclase del mismo para realizar la sincronización de los datos, y también debería considerar la sincronización del acceso al objeto FileStream (probablemente a través de una declaración de lock ).

Actualización: al responder a esta pregunta implementé algo similar: una situación en la que un archivo se descargaba en segundo plano y también se cargaba al mismo tiempo. Utilicé memorias de memoria, y publiqué un gist que tiene código de trabajo. (Es GPL, pero eso podría no ser importante para usted, en cualquier caso, puede usar los principios para hacer lo suyo).