2016-02-10 11 views
8

Ho un programma semplice per leggere un file utilizzando StreamReader e elaborarlo riga per riga. Ma il file che sto leggendo può a volte trovare in una cartella di rete. Mi sono imbattuto mentre eseguivo dei test con un file di questo tipo, che se la connessione di rete venisse persa a un certo punto mentre sto leggendo, rimarrà nella stessa linea ancora e ancora in loop su un loop infinito, risultando la stessa linea del risultato da stream.ReadLine().StreamReader.ReadLine si bloccherà in un ciclo infinito

C'è un modo per trovare quando fileHandle non è disponibile dal flusso stesso? Mi aspettavo che un tipo FileNotAvailableException di un'eccezione si attivasse quando il filehandle viene perso da StreamReader.

Ecco il mio frammento di codice ...

 string file = @"Z://1601120903.csv"; //Network file 
     string line; 
     StringBuilder stb = new StringBuilder();  
     StreamReader stream = new StreamReader(file, Encoding.UTF8, true, 1048576); 
     do 
     { 
      line = stream.ReadLine(); 
      // Do some work here 
     } while (line != ""); 
+3

StreamReader non può "perdere" l'handle. Se in effetti non è possibile utilizzare i dati memorizzati nella cache e deve raggiungere la rete per ottenere il contenuto del file, la chiamata di ReadFile() sottostante avrà esito negativo e si otterrà System.IOException. Che riporta "Errore di rete", una delle tante cose che possono andare storte durante la lettura dei file. Prenderesti l'eccezione e informerai l'utente in modo che possa fare tutto il necessario per correggere il problema. –

+1

Sto meditando se chiudere questo perché qui c'è un bug che non è visibile in questo codice. Il codice mostrato qui deve essere una versione semplificata del codice reale. – usr

+0

@ HansPassant, sì, inizialmente ho pensato anche la stessa cosa. Ma se si esegue questa riga di codice, si verificherà il problema. Non lancia un'eccezione perché continua a lanciarmi la stessa linea indefinitamente. – Asanka

risposta

7

approccio corretto 1 (EndOfStream):

using(StreamReader sr = new StreamReader(...)) { 
    while(!sr.EndOfStream) { 
     string line = sr.ReadLine(); 
     Console.WriteLine(line); 
    } 
} 

approccio corretto 2 (Peek)

using(StreamReader sr = new StreamReader(...)) { 
    while(sr.Peek() >= 0) { 
     string line = sr.ReadLine(); 
    } 
} 

Nota: che non è corretto minaccia una stringa vuota come la fine del file.

se la connessione di rete ha perso a un certo punto, mentre io sto leggendo, resterò nella stessa linea ancora e ancora looping in un ciclo infinito dal conseguente stessa linea il risultato da stream.ReadLine (

Ho controllato questo scenario in questo momento - il System.IO.IOException ("Il percorso di rete non è stato trovato."} Dovrebbe essere lanciato in questo caso.

Il riavvolgimento con un blocco di prova non risolverà il problema, vero?

In questo caso è possibile interrompere la lettura come segue:

string line; 
do { 
    try { 
     line = sr.ReadLine(); 
     // Do some work here 
    } 
    catch(System.IO.IOException) { 
     break; 
    } 
} while(line != null); 
+0

Ho controllato queste due proprietà. Dopo che il filehandle è caduto a causa di problemi di rete, entrambe queste condizioni restituiscono true e stream.ReadLine() restituisce la stessa riga ancora e ancora sulla riga variabile. – Asanka

+0

@Asanka Ho aggiornato le mie risposte con alcuni risultati dei test di vita reale. – DmitryG

+0

Strano. Non mi ha fatto alcuna eccezione. Hai interrotto la connessione mentre ti trovavi nel mezzo dell'operazione di lettura dei file? – Asanka

17

Confronta con null non con stringa vuota:

https://msdn.microsoft.com/en-us/library/system.io.streamreader.readline(v=vs.110).aspx

Valore restituito Tipo: System.String riga successiva da il flusso di input, o null se viene raggiunta la fine del flusso di input.

do 
    { 
     line = stream.ReadLine(); 
     // Do some work here 
    } while (line != null); 

Un approccio migliore, tuttavia, è quello di lasciare .Net fare il lavoro (riga per la lettura di file di linea) per voi e rilasciare tutti i lettori:

foreach (String line in File.ReadLines(file)) { 
    // Do some work here 
    } 
+1

migliorerebbe il codice per usare qualcosa come 'string.IsNullOrEmpty (riga)'? – terbubbs

+4

@terbubbs: no, una * stringa vuota * può apparire nel bel mezzo del file –

+0

Ma il problema non è con il controllo di null o vuoto. Dopo che il filehandle è caduto a causa di problemi di rete, stream.ReadLine() restituisce la stessa riga ancora e ancora sulla riga variabile. Non sarà mai vuoto o nullo – Asanka

0

Assumendo il file non dovrebbe cambia mentre lo leggi e non è enorme, potresti prendere in considerazione di copiarlo in un file temporaneo (localmente) e poi lavorarci senza interferenze.

Se si desidera ottenere indice del luogo avete raggiunto questo potrebbe aiutare: How to know position(linenumber) of a streamreader in a textfile?

+0

La copia del file localmente sembra una buona soluzione. Ma potrebbe esserci la possibilità che il file stesso sia piuttosto grande. – Asanka

+1

Questo non risolve il problema che ha. Si presuppone erroneamente che la stessa riga possa essere riprodotta ripetutamente. Invece, questo è un bug con il suo codice. – usr

+0

@Asanka come ho detto controllare se è possibile copiare un file, e se si vuole comunque tenere traccia dell'indice del lettore attuale si dovrebbe usare la soluzione che ho aggiunto. –

3

Se si scrive con un while -loop:

while ((line = sr.ReadLine()) != null) 
{ 
    Console.WriteLine(line); 
} 

Source

1

Un altro modo sarebbe quello di utilizzare File.ReadAllLines() e si prenderà cura di file di apertura e la lettura di tutte le linee e closig il file e può anche gestire lo scenario quando si perde la connessione di rete.

var lines = File.ReadAllLines("Z://1601120903.csv"); 

foreach(line in lines) 
{ 
// Do some work 
}