2010-09-01 24 views
8

Estoy usando FileSystemWatcher para verificar cuándo se modifica o elimina un archivo, pero me pregunto si hay alguna manera de verificar cuándo un archivo es leído por otra aplicación.Detectar archivo leído en C#

Ejemplo: Tengo el archivo C: \ test.txt en mi disco duro y lo veo usando FileSystemWatcher. Otro programa (que no está bajo mi control) va a leer ese archivo; Me gustaría detectar ese evento y, si es posible, verificar qué programa está leyendo el archivo y luego modificar el contenido del archivo en consecuencia.

+1

esto parece un requisito extraño. puedes expandirte en lo que tu objetivo final es un poco más. – luke

+0

@luke - Lo que me gustaría hacer es encriptar una parte del archivo, pero cuando una aplicación web (que no tengo control) va a leer ese archivo, descifraré la parte encriptada para ello. –

+0

parece una mejor manera de resolver esto sería simplemente configurar un control de acceso más detallado para que solo la aplicación web (y su aplicación) pueda leer el archivo, entonces no tendría que encriptarlo en absoluto. – luke

Respuesta

4

Parece que desea escribir en su archivo de registro cuando su archivo de registro se lee externamente, o algo por el estilo. Si ese es el caso, hay un valor de NotifyFilters, LastAccess. Asegúrese de que esté configurado como uno de los indicadores en su propiedad FileSystemWatcher.NotifyFilter. Un cambio en el último tiempo de acceso disparará el evento Changed en FileSystemWatcher.

Actualmente, FileSystemWatcher no permite diferenciar directamente entre una lectura y un cambio; ambos activan el evento modificado en función del "cambio" de LastAccess. Por lo tanto, sería inviable observar las lecturas en una gran cantidad de archivos. Sin embargo, parece que sabe qué archivo está viendo, por lo que si tiene un objeto FileInfo para ese archivo y FileSystemWatcher activó su evento Changed, podría obtener uno nuevo y comparar los valores de LastAccessTime. Si el tiempo de acceso cambió, y LastWriteTime no lo hizo, su archivo solo se está leyendo.

Ahora, en términos más simples, los cambios que realice en el archivo mientras se está leyendo no se mostrarán inmediatamente en la otra aplicación, ni podrá "llegar primero", bloquee el archivo y escribe en él antes de que lo vean. Por lo tanto, no puede usar FileSystemWatcher para "interceptar" una solicitud de lectura y mostrar el contenido que desea que esa aplicación vea. La única forma en que el usuario de otra aplicación puede ver lo que acaba de escribir es si la aplicación también está mirando el archivo y vuelve a cargar el archivo. Eso disparará otro evento modificado, causando un bucle infinito siempre que la otra aplicación continúe recargando el archivo.

También recibirá un evento Modificado para una lectura y una escritura. Abrir un archivo en un editor de texto (prácticamente cualquiera lo hará), hacer algunos cambios, luego guardar disparará dos eventos modificados si está buscando cambios en el último tiempo de acceso. El primero se disparará cuando el editor abra el archivo; en ese momento, es posible que no pueda decir que ocurrirá una escritura, de modo que si está buscando accesos puros de solo lectura al archivo, entonces usted es SOL.

-2

Un poco snippet que he encontrado útil para detectar cuando otro proceso tiene un bloqueo:

static bool IsFileUsedbyAnotherProcess(string filename) 
     { 
      try 
      { 
       using(var file = File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.None)) 
       { 
       } 
      } 
      catch (System.IO.IOException exp) 
      { 
       return true; 
      } 
      return false; 
     } 
+3

Solo funciona si la otra aplicación lo ha bloqueado para escribir. Abrir un archivo para leer no necesariamente lo bloquea. – KeithS

+3

¡Egad! Esa función deja el archivo abierto hasta que se recolecta basura, lo que significa que nadie más puede abrirlo sin compartirlo. – Gabe

+2

¿Y quién cierra File.Open() aquí? – kofucii

2

La forma más sencilla que puedo pensar para hacer esto sería con un temporizador (System.Threading.Timer) cuyos cheques de devolución de llamada y almacena la última

System.IO.File.GetLastAccessTime(path) 

Algo así (tal vez con un poco más de bloqueo ...)

public class FileAccessWatcher 
{ 

public Dictionary<string, DateTime> _trackedFiles = new Dictionary<string, DateTime>(); 

private Timer _timer; 

public event EventHandler<EventArgs<string>> FileAccessed = delegate { }; 

public FileAccessWatcher() 
{ 
    _timer = new Timer(OnTimerTick, null, 500, Timeout.Infinite); 
} 

public void Watch(string path) 
{ 
    _trackedFiles[path] = File.GetLastAccessTime(path); 
} 

public void OnTimerTick(object state) 
{ 
    foreach (var pair in _trackedFiles.ToList()) 
    { 
     var accessed = File.GetLastAccessTime(pair.Key); 
     if (pair.Value != accessed) 
     { 
      _trackedFiles[pair.Key] = accessed; 
      FileAccessed(this, new EventArgs<string>(pair.Key)); 
     } 
    } 

    _timer.Change(500, Timeout.Infinite); 
} 
} 
2

Hay programa SysInternals' FileMon ... se puede rastrear cada acceso a los archivos en el sistema. Si puede encontrar su fuente y entender qué ganchos de win32 usa, puede ordenar esas funciones en C# y obtener lo que desea.

0

Sí, utilizando el controlador de filtro del sistema de archivos puede capturar todas las solicitudes de lectura, analizarlas e incluso sustituir los datos que se leen. El desarrollo de dicho controlador es posible, pero requiere mucho tiempo y es complicado. Ofrecemos un producto llamado CallbackFilter, que incluye un controlador listo para usar y le permite implementar su lógica de negocios de filtrado en modo de usuario.

Cuestiones relacionadas