Usando archivo proyectado en memoria y FileSystemWatcher para detectar nuevas entradas a archivo de registro

StackOverflow https://stackoverflow.com/questions/4198692

  •  11-10-2019
  •  | 
  •  

Pregunta

Tengo un archivo de registro que está escrita por una aplicación de 3 ª parte y me gustaría que mi solicitud de "leer" ese archivo de registro en / en tiempo casi real, analizar la nuevas entradas de registro y actuar sobre ciertos eventos.

Mi pensamiento era que podía lograr esto con una combinación de FileSystemWatcher (a cambios en los archivos de la señal) y el archivo proyectado en memoria (para seguir leyendo desde un cierto desplazamiento).

Sin embargo, ya que esta es la primera vez que estoy usando MemoryMappedFiles me topo con algunas cuestiones que surgen probablemente por no entender el concepto correctamente (por ejemplo, no soy capaz de abrir el archivo existente, ya que está en uso por otro proceso ).

Me preguntaba si alguien tiene un ejemplo de cómo utilizar MemoryMappedFiles para leer un archivo que está bloqueado por otro proceso?

Gracias,

Tom

EDIT:

A partir de los comentarios, parece que archivos de memoria asignada no me ayuda para acceder a los archivos que tienen un bloqueo exclusivo. Sin embargo, las herramientas de "cola", como, por ejemplo, BareTail (http://www.baremetalsoft.com/baretail/index.php) son capaces de hacer eso. No tiene ningún problema al leer el archivo que tiene un bloqueo exclusivo de otra aplicación en intervalos de 1 s). Por lo tanto, tiene que haber alguna manera de hacer esto?

Desambiguacióneditar

Para responder a mi propia pregunta, el truco en la apertura de un archivo bloqueado es, la creación de la FileStream con las banderas de acceso siguientes:

fileStream = new System.IO.FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Delete | FileShare.ReadWrite);
¿Fue útil?

Solución

Para responder a mi propia pregunta, el truco en la lectura de un archivo bloqueado está creando el FileStream con las banderas de acceso siguientes:

FileStream fileStream = new System.IO.FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Delete | FileShare.ReadWrite);

Ahora es sólo una cuestión de hacer ya sea a base de votación intervalo o en busca de eventos de cambio FileSystemWatcher para detectar cambios en los archivos

Otros consejos

No estoy seguro de si MemoryMappedFiles van a ayudarle. Echar un vistazo a FileStream:

var stream = new FileStream(path, FileMode.Open, FileShare.Read);
stream.Seek(offset, SeekOrigin.Begin);

A pesar de si la aplicación de 3ra parte tiene el archivo bloqueado exclusivamente, no hay mucho que se puede hacer al respecto ...

[Begin segundo EDIT]

Una idea más ...

Si la aplicación de terceros pasa a utilizar un marco de registro como Nlog, log4net, o System.Diagnostics, aún se podía escribir su propio destino / Appender de / TraceListener y enrutar los mensajes en alguna parte que usted podría mirar a ellos (como una archivo que no está abierto de manera exclusiva, a otro proceso, etc.).

Si su aplicación de terceros está utilizando un marco de registro, es probable que hubiera oído hablar de él a estas alturas; -)

[Fin segunda EDIT]

[Begin EDIT]

creo que leí mal la pregunta. Sonaba en un primer momento como si estuviera utilizando un biblioteca de terceros que se había implementado logging y que quería hacer este análisis dentro del programa que estaba generando el registro. Tener volver a leer su pregunta, que suena como usted quiere "escuchar" el archivo de registro desde fuera de la aplicación. Si ese es el caso, mi respuesta probablemente no le ayude. Lo sentimos.

[Fin EDIT]

No tengo nada que ofrecer sobre MemoryMappedFiles, pero me pregunto si se puede lograr lo que está después escribiendo un escucha personalizado / target / appender para el sistema de registro de tercera parte?

Por ejemplo, si está utilizando Nlog, se podría escribir una costumbre de destino y dirigir todos los mensajes de registro de allí (y al mismo tiempo dirigir a los "reales" Target (s)). De esta manera se obtiene grieta en cada mensaje de registro, ya que se registra (por lo que es en realidad en tiempo real, no casi en tiempo real). Usted podría hacer lo mismo con log4net y System.Diagnostics.

Tenga en cuenta que Nlog incluso tiene un objetivo "methodCall". Para el uso que uno sólo tiene que escribir un método estático con la firma correcta. No sé si log4net tiene un concepto similar a esta.

Esto parece que sería más fácil de hacer funcionar de forma fiable que tratar de leer y analizar el archivo de registro, ya que está siendo escrito por el software de terceros.

Si el archivo está "en uso", no hay nada que se pueda hacer al respecto. Realmente está "en uso". MemoryMappedFiles son, ya sea para leer grandes cantidades de datos de la unidad o compartir datos con otros programas. Se ayuda no va a moverse por la limitación "en uso".

Los archivos Memorymapped están bajo las mismas restricciones que el FileStream inicializar con, asegúrese de que usted hace funcionar su asignados a la memoria-File como esto

var readerStream = new FileStream (path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);

var mmf = MemoryMappedFile.CreateFromFile (readerStream, null, 0, MemoryMappedFileAccess.Read, null, HandleInheritability.None, false);

Si algún otro proceso ha bloqueado por completo incluso de escribir estás en la mala suerte, no estoy seguro si hay una forma de evitar eso. Tal vez algún utilizar temporizador do detectar cuando el proceso ha dejado de escribir a la misma.

he hecho algo similar sólo para el seguimiento de los archivos de registro en una consola (a diferencia de procesamiento), pero los principios son los mismos. Al igual que usted, yo uso un FileSystemWatcher, y la lógica es importante en mi controlador de eventos OnChanged:

case WatcherChangeTypes.Changed:
{
    System.IO.FileInfo fi = new FileInfo(e.FullPath);

    long prevLength;

    if (lastPositions.TryGetValue(e.FullPath, out prevLength))
    {
        using (System.IO.FileStream fs = new FileStream(
           e.FullPath, FileMode.Open, FileAccess.Read))
        {
            fs.Seek(prevLength, SeekOrigin.Begin);
            DumpNewData(fs, (int)(fi.Length - prevLength));
            lastPositions[e.FullPath] = fs.Position;
        }
    }
    else
      lastPositions.Add(e.FullPath, fi.Length);

    break;
}

donde lastPositions es

Dictionary<string, Int64> lastPositions = new Dictionary<string, long>();

y DumpNewData es simplemente

private static void DumpNewData(FileStream fs, int bytesToRead)
{
    byte[] bytesRead = new byte[bytesToRead];
    fs.Read(bytesRead, 0, bytesToRead);
    string s = System.Text.ASCIIEncoding.ASCII.GetString(bytesRead);
    Console.Write(s);
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top