2010-08-10 14 views
70

Tengo un servicio de Windows escribe su registro en un archivo de texto en un formato simple.¿Cómo puedo leer un archivo de texto sin bloquearlo?

Ahora, voy a crear una pequeña aplicación para leer el registro del servicio y mostrar tanto el registro existente como el agregado como vista en vivo.

El problema es que el servicio bloquea el archivo de texto para agregar las nuevas líneas y, al mismo tiempo, la aplicación del espectador bloquea el archivo para su lectura.

El código de servicio:

void WriteInLog(string logFilePath, data) 
{ 
    File.AppendAllText(logFilePath, 
         string.Format("{0} : {1}\r\n", DateTime.Now, data)); 
} 

El Código espectador:

int index = 0; 
private void Form1_Load(object sender, EventArgs e) 
     { 
      try 
      { 
       using (StreamReader sr = new StreamReader(logFilePath)) 
       { 
        while (sr.Peek() >= 0) // reading the old data 
        { 
         AddLineToGrid(sr.ReadLine()); 
         index++; 
        } 
        sr.Close(); 
       } 

       timer1.Start(); 
      } 
      catch (Exception ex) 
      { 
       MessageBox.Show(ex.Message); 
      } 
     } 


private void timer1_Tick(object sender, EventArgs e) 
     { 
      using (StreamReader sr = new StreamReader(logFilePath)) 
      { 
       // skipping the old data, it has read in the Form1_Load event handler 
       for (int i = 0; i < index ; i++) 
        sr.ReadLine(); 

       while (sr.Peek() >= 0) // reading the live data if exists 
       { 
        string str = sr.ReadLine(); 
        if (str != null) 
        { 
         AddLineToGrid(str); 
         index++; 
        } 
       } 
       sr.Close(); 
      } 
     } 

¿Hay algún problema en mi código de lectura y escritura de manera?

¿Cómo resolver el problema?

+0

Posible duplicado de [¿Puedo evitar que StreamReader bloquee un archivo de texto mientras está en uso?] (Https://stackoverflow.com/questions/1606349/can-i-prevent-a-streamreader-from-locking -a-text-file-while-it-is-in-use) –

Respuesta

94

usted necesita para asegurarse de que tanto el servicio y el lector abra el archivo de registro de forma no exclusiva. Prueba esto:

Para el uso de los servicios de una instancia creada FileStream de la siguiente manera:

var outStream = new FileStream(logfileName, FileMode.Open, 
           FileAccess.Write, FileShare.ReadWrite); 

Para el lector utilice la misma, pero cambiar el acceso a los archivos:

var inStream = new FileStream(logfileName, FileMode.Open, 
           FileAccess.Read, FileShare.ReadWrite); 

Buena suerte!

+0

También está la versión de ReadLines() en http://stackoverflow.com/questions/5338450/file-readlines-without-locking-it – Colin

+0

Perfecto - Pensé que File.Open() con FileAccess.Read era suficiente, pero no es. Esto es, sin embargo. :) – neminem

2

¿Has intentado copiar el archivo y luego leerlo?

Simplemente actualice la copia cada vez que se realicen grandes cambios.

+1

Lo he intentado y no es la mejor solución. Copiar el archivo lleva demasiado tiempo, ya que un archivo de 4 MB tarda unos 20 segundos. – Seichi

6

El problema es que cuando escribe en el registro está bloqueando exclusivamente el archivo para que su StreamReader no pueda abrirlo en absoluto.

Debe intentar abrir el archivo en modo solo lectura.

using (FileStream fs = new FileStream("myLogFile.txt", FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) 
{ 
    using (StreamReader sr = new StreamReader(fs)) 
    { 
     while (!fs.EndOfStream) 
     { 
      string line = fs.ReadLine(); 
      // Your code here 
     } 
    } 
} 
+0

Como ahora sé, 'File.ReadAllText()' falla con el modo de solo lectura. –

+0

@modosansreves sí, eliminé esa parte de la respuesta ya que [docs] (http://msdn.microsoft.com/en-us/library/ms143368 (v = vs.100) .aspx) indica que lanzará un 'UnauthorizedAccessException' si el archivo es de solo lectura, debe haberlo perdido al momento de responder. – James

26

Establece explícitamente el modo de compartir mientras lee el archivo de texto.

using (FileStream fs = new FileStream(logFilePath, 
             FileMode.Open, 
             FileAccess.Read,  
             FileShare.ReadWrite)) 
{ 
    using (StreamReader sr = new StreamReader(fs)) 
    { 
     while (sr.Peek() >= 0) // reading the old data 
     { 
      AddLineToGrid(sr.ReadLine()); 
      index++; 
     } 
    } 
} 
+2

no es necesario cerrar explícitamente la secuencia, ya que StreamReader.Dispose lo cierra automáticamente. – nothrow

+2

Creo que el recurso compartido de archivos debe establecerse en AMBAS secuencias de lectura y escritura, y no solo leer. –

10
new StreamReader(File.Open(logFilePath, 
          FileMode.Open, 
          FileAccess.Read, 
          FileShare.ReadWrite)) 

-> esto no bloquea el archivo.

+0

Parece que funciona al leer datos. Al escribir, aparece el error de archivo bloqueado. – webzy

5

Recuerdo haber hecho lo mismo hace un par de años. Después de algunas consultas Google I encontré esto:

FileStream fs = new FileStream(@”c:\test.txt”, 
            FileMode.Open, 
            FileAccess.Read,   
            FileShare.ReadWrite); 

es decir, utilizar el atributo FileShare.ReadWrite en FileStream().

(se encuentra en Balaji Ramesh's blog)

0

Este método le ayudará a leer más rápido y un archivo de texto sin bloquearlo.

private string ReadFileAndFetchStringInSingleLine(string file) 
    { 
     StringBuilder sb; 
     try 
     { 
      sb = new StringBuilder(); 
      using (FileStream fs = File.Open(file, FileMode.Open)) 
      { 
       using (BufferedStream bs = new BufferedStream(fs)) 
       { 
        using (StreamReader sr = new StreamReader(bs)) 
        { 
         string str; 
         while ((str = sr.ReadLine()) != null) 
         { 
          sb.Append(str); 
         } 
        } 
       } 
      } 
      return sb.ToString(); 
     } 
     catch (Exception ex) 
     { 
      return ""; 
     } 
    } 

Espero que este método te ayude.

Cuestiones relacionadas