Asanka
Asanka

Reputation: 559

StreamReader.ReadLine will hang in an infinite loop

I have a simple program to read a file using the StreamReader and process it line by line. But the file I am reading may sometimes locate in a network folder. I came across while doing some testing with such a file, that if the network connection lost at some point while I am reading, it'll stay in the same line again and again looping in an infinite loop by resulting the same line as the result from stream.ReadLine().

Is there a way I can find when the fileHandle is not available from the stream itself? I was expecting a FileNotAvailableException kind of an exception would fire when the filehandle is lost from the StreamReader.

Here's my code snippet...

        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 != "");

Upvotes: 13

Views: 10567

Answers (6)

otaviodecampos
otaviodecampos

Reputation: 1894

If your stream is a NetworkStream, the ReadLine method will expect more content from the stream, if it reached at end, indefinitely. I think, and according to the StreamReader documentation, it is designed to work only with local file streams. In this case, you can read bytes directly from the NetworkStream.

https://learn.microsoft.com/pt-br/dotnet/api/system.net.sockets.networkstream.read?view=netcore-3.1#System_Net_Sockets_NetworkStream_Read_System_Span_System_Byte__

Upvotes: 0

Viru
Viru

Reputation: 2246

One more way would be to use File.ReadAllLines() and it will take care of opening file and reading all lines and closig the file and may also handle scenario when network connection is lost.

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

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

Upvotes: 1

DmitryG
DmitryG

Reputation: 17850

Correct approach 1 (EndOfStream) :

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

Correct approach 2 (Peek)

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

Note: that it is incorrect to threat an empty string as end of file.

if the network connection lost at some point while I am reading, it'll stay in the same line again and again looping in an infinite loop by resulting the same line as the result from stream.ReadLine()

I've checked this scenario right now - the System.IO.IOException ("The network path was not found."} should be thrown in this case.

Wrapping this with a try catch block will not fix my problem, will it?

In this case you can break the reading as follows:

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

Upvotes: 9

Dmitrii Bychenko
Dmitrii Bychenko

Reputation: 186668

Compare with null not with empty string:

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

Return Value Type: System.String The next line from the input stream, or null if the end of the input stream is reached.

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

A better approach, however, is to let .Net do the work (line by line file reading) for you and drop all readers:

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

Upvotes: 19

Felix Av
Felix Av

Reputation: 1254

Assuming the file shouldn't change while you reading it and it's not huge, you might want to consider to copy it to a temp file (locally) and then work on it without interference.

If you want to get index of the place you reached this might help: How to know position(linenumber) of a streamreader in a textfile?

Upvotes: 0

diiN__________
diiN__________

Reputation: 7656

If you write it with a while-loop:

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

Source

Upvotes: 4

Related Questions