2010-09-01 16 views
8

Sto usando FileSystemWatcher per controllare quando un file viene modificato o cancellato, ma mi chiedo se ci sia un modo per controllare quando un file viene letto da un'altra applicazione.Rileva file letta in C#

Esempio: Ho il file C: \ test.txt sul mio disco fisso e lo sto guardando utilizzando FileSystemWatcher. Un altro programma (non sotto il mio controllo) va a leggere quel file; Vorrei prendere quell'evento e, se possibile, controllare quale programma sta leggendo il file, quindi modificare di conseguenza il contenuto del file.

+1

questo sembra uno strano requisito. puoi espandere ciò che il tuo obiettivo finale è un po 'di più. – luke

+0

@luke - Quello che vorrei fare è criptare una parte del file, ma quando un'applicazione web (che non ho il controllo) va a leggere quel file, decrittò la porzione crittografata per esso. –

+0

sembra che un modo migliore per risolvere questo problema sia semplicemente impostare un controllo di accesso a grana più fine in modo che solo l'app Web (e la tua app) possano leggere il file, quindi non sarà necessario crittografarlo affatto. – luke

risposta

4

Sembra che tu voglia scrivere sul tuo file di registro quando il tuo file di registro viene letto esternamente, o qualcosa del genere. Se questo è il caso, c'è un valore NotifyFilters, LastAccess. Assicurarsi che questo sia impostato come uno dei flag nella proprietà FileSystemWatcher.NotifyFilter. Una modifica nell'ultimo tempo di accesso attiverà quindi l'evento Changed su FileSystemWatcher.

Attualmente FileSystemWatcher non consente di distinguere direttamente tra una lettura e una modifica; entrambi attivano l'evento Changed in base al "cambiamento" in LastAccess. Quindi, sarebbe impossibile guardare le letture su un gran numero di file. Tuttavia, sembra che tu sappia quale file stai guardando, quindi se hai un oggetto FileInfo per quel file e FileSystemWatcher ha attivato l'evento Changed, puoi ottenerne uno nuovo e confrontare i valori LastAccessTime. Se il tempo di accesso è cambiato e LastWriteTime no, il tuo file viene solo letto.

Ora, in termini più semplici, le modifiche apportate al file mentre vengono lette non vengono visualizzate immediatamente nell'altra app, né si sarà in grado di "arrivare prima", bloccare il file e scrivici prima che lo vedano. Pertanto, non è possibile utilizzare FileSystemWatcher per "intercettare" una richiesta di lettura e mostrare il contenuto che l'app deve vedere. L'unico modo in cui l'utente di un'altra applicazione può vedere ciò che hai appena scritto è se l'applicazione sta anche guardando il file e ricarica il file. Questo genererà un altro evento Changed, causando un ciclo infinito finché l'altra applicazione continuerà a ricaricare il file.

Si otterrà anche un evento modificato per una lettura e una scrittura. Aprendo un file in un editor di testo (praticamente qualsiasi cosa farà), apportando alcune modifiche, quindi il salvataggio genererà due eventi modificati se stai cercando le modifiche al tempo dell'ultimo accesso. Il primo si spegnerà quando il file verrà aperto dall'editor; a quel tempo, potresti non essere in grado di dire che una scrittura avverrà, quindi se stai cercando un accesso in sola lettura al file, allora sei SOL.

-2

Un po snippet che ho trovato utile per rilevare quando un altro processo ha un blocco:

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

Funziona solo se l'altra applicazione lo ha bloccato per la scrittura. Aprire un file da leggere non necessariamente lo blocca. – KeithS

+3

Egad! Questa funzione lascia aperto il file fino a quando non viene raccolta automaticamente, il che significa che nessun altro può aprirlo senza la condivisione abilitata. – Gabe

+2

E chi chiude File.Open() qui? – kofucii

2

Il modo più semplice che posso pensare di fare questo sarebbe stato con un timer (System.Threading.Timer) i cui controlli callback e memorizza l'ultimo

System.IO.File.GetLastAccessTime(path) 

Qualcosa di simile (magari con un po 'più di chiusura ...)

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

C'è programma SysInternals FileMon ... si può tracciare ogni accesso ai file nel sistema. Se riesci a trovarne l'origine e a capire quali ganci win32 utilizza, puoi eseguire il marshalling di tali funzioni in C# e ottenere ciò che desideri.

0

Sì, utilizzando il driver del filtro del file system è possibile catturare tutte le richieste di lettura, analizzarle e persino sostituire i dati letti. Lo sviluppo di tale driver è possibile, ma richiede molto tempo e complicazioni. Offriamo un prodotto chiamato CallbackFilter, che include un driver pronto all'uso e consente di implementare la logica di business del filtro in modalità utente.