2009-09-11 9 views
16

In C# /. NET (su Windows) c'è un modo per leggere un file "crescente" utilizzando un flusso di file? La lunghezza del file sarà molto piccola quando si apre il filestream, ma il file verrà scritto da un altro thread. Se/quando il filestream "raggiunge" l'altro thread (ad esempio, quando Read() restituisce 0 byte letti), voglio mettere in pausa per consentire al file di bufferizzare un po ', quindi continuare a leggere.Leggi da un file in crescita in C#?

Non voglio veramente usare uno FilesystemWatcher e continuare a creare nuovi flussi di file (come è stato suggerito per i file di registro), poiché questo non è un file di registro (è un file video che viene codificato al volo) e le prestazioni è un problema.

Grazie,
Robert

+0

Ho aggiornato la mia risposta. –

risposta

6

È possibile eseguire questa operazione, ma è necessario tenere traccia delle posizioni di lettura e scrittura del file utilizzando Stream.Seek e con la sincronizzazione appropriata tra i thread. In genere si utilizza una sottoclasse EventWaitHandle per eseguire la sincronizzazione per i dati e si dovrebbe anche considerare la sincronizzazione per l'accesso all'oggetto FileStream stesso (probabilmente tramite un'istruzione lock).

Aggiornamento: In risposta a this question Ho implementato qualcosa di simile - una situazione in cui un file veniva scaricato in background e veniva anche caricato contemporaneamente. Ho usato i buffer di memoria e pubblicato un gist che ha un codice funzionante. (È GPL ma potrebbe non essere importante per te - in ogni caso puoi usare i principi per fare le tue cose.)

+0

Prenderò un'occhiata a questo ... per i calci, potrebbe essere più semplice scrivere semplicemente il risultato della codifica in memoria (cioè usando un doppio buffer) e poi inviarlo alla rete e al file di cache contemporaneamente? –

4

Il modo in cui ho risolto questo sta usando la classe DirectoryWatcher/FileSystemWatcher, e quando si innesca sul file che si desidera si apre un FileStream e leggere fino alla fine. E quando ho finito di leggere, ho salvato la posizione del lettore, quindi la prossima volta che i trigger DirectoryWatcher/FilesystemWatcher apro un flusso imposta la posizione a dove ero l'ultima volta.

Chiamare FileStream.length è molto lento, non ho avuto problemi di prestazioni con la mia soluzione (stavo leggendo un "log" che andava da 10mb a 50 ish).

Per me la soluzione che descrivo è molto semplice e di facile manutenzione, proverei e la descriverò. Non penso che otterrai alcun problema di prestazioni basato su di esso. Lo faccio quando ppl sta giocando a un gioco multi-thread, prendendo la loro intera CPU e nessuno si è lamentato che il mio parser sia più esigente dei parser concorrenti.

+1

La domanda sconta in modo specifico utilizzando un osservatore, a causa di problemi di prestazioni. –

+0

Sì, ho notato. aggiunto di più alla mia risposta in merito alla preformance. – EKS

+0

Non devi necessariamente chiamare FileStream.Length nel lettore se tutto ciò che stai facendo è leggere il più lontano possibile, quindi aspettare altri dati. Che tipo di latenza stai vedendo per l'osservatore che si attiva? Questo cambia in base al carico della macchina? –

2

Un'altra cosa che potrebbe essere utile è che la classe FileStream ha una proprietà chiamata ReadTimeOut che è definito come:

Ottiene o imposta un valore, in millisecondi, che determina per quanto tempo lo stream tenterà di leggere prima del timeout. (ereditato da Stream)

Questo può essere utile in quanto quando le tue letture raggiungono le tue scritture, il thread che esegue le letture può sospendere mentre il buffer di scrittura viene scaricato. Certianamente varrebbe la pena di scrivere un piccolo test per vedere se questa proprietà potrebbe aiutare la tua causa in qualche modo.

Le operazioni di lettura e scrittura si verificano sullo stesso oggetto? In tal caso, è possibile scrivere le proprie astrazioni sul file e quindi scrivere il codice di comunicazione cross-thread in modo tale che il thread che sta eseguendo le scritture e notificare al thread l'esecuzione delle letture quando viene eseguito in modo che il thread che esegue le letture sappia quando interrompere la lettura quando raggiunge EOF.

+0

In che modo questa risposta ha +3 se l'impostazione di ReadTimeOut su FileStream genera un'eccezione? :S –

4

questo ha lavorato con uno StreamReader intorno un file, con le seguenti fasi:

  1. nel programma che scrive il file, aprirlo con la condivisione di lettura, in questo modo:

    var out = new StreamWriter(File.Open("logFile.txt", FileMode.OpenOrCreate, FileAccess.Write, FileShare.Read)); 
    
  2. Nel programma che legge il file, aprirlo con la condivisione di lettura-scrittura, in questo modo:

    using (FileStream fileStream = File.Open("logFile.txt", FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) 
    using (var file = new StreamReader(fileStream)) 
    
  3. Prima di accedere al flusso di input, controllare se è stata raggiunta la fine e, in tal caso, attendere un po 'di tempo.

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