Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Bug in the File.ReadLines(..) method of the .net framework 4.0

Tags:

c#

.net

c#-4.0

This code :

IEnumerable<string> lines = File.ReadLines("file path");
foreach (var line in lines)
{
    Console.WriteLine(line); 
}
foreach (var line in lines)
{ 
    Console.WriteLine(line); 
} 

throws an ObjectDisposedException : {"Cannot read from a closed TextReader."} if the second foreach is executed. It seems that the iterator object returned from File.ReadLines(..) can't be enumerated more than once. You have to obtain a new iterator object by calling File.ReadLines(..) and then use it to iterate.

If I replace File.ReadLines(..) with my version(parameters are not verified, it's just an example):

public static IEnumerable<string> MyReadLines(string path)
{
    using (var stream = new TextReader(path))
    {
        string line;
        while ((line = stream.ReadLine()) != null)
        {
            yield return line;
        }
    }
}

it's possible to iterate more than once the lines of the file.

An investigation using .Net Reflector showed that the implementation of the File.ReadLines(..) calls a private File.InternalReadLines(TextReader reader) that creates the actual iterator. The reader passed as a parameter is used in the MoveNext() method of the iterator to get the lines of the file and is disposed when we reach the end of the file. This means that once MoveNext() returns false there is no way to iterate a second time because the reader is closed and you have to get a new reader by creating a new iterator with the ReadLines(..) method.In my version a new reader is created in the MoveNext() method each time we start a new iteration.

Is this the expected behavior of the File.ReadLines(..) method?

I find troubling the fact that it's necessary to call the method each time before you enumerate the results. You would also have to call the method each time before you iterate the results of a Linq query that uses the method.

like image 457
Adrian Constantin Avatar asked Feb 20 '10 23:02

Adrian Constantin


3 Answers

I know this is old, but i actually just ran into this while working on some code on a Windows 7 machine. Contrary to what people were saying here, this actually was a bug. See this link.

So the easy fix is to update your .net framefork. I thought this was worth updating since this was the top search result.

like image 161
richard Avatar answered Oct 15 '22 06:10

richard


I don't think it's a bug, and I don't think it's unusual -- in fact that's what I'd expect for something like a text file reader to do. IO is an expensive operation, so in general you want to do everything in one pass.

like image 5
jmoreno Avatar answered Oct 15 '22 05:10

jmoreno


It isn't a bug. But I believe you can use ReadAllLines() to do what you want instead. ReadAllLines creates a string array and pulls in all the lines into the array, instead of just a simple enumerator over a stream like ReadLines does.

like image 1
Stephen M. Redd Avatar answered Oct 15 '22 05:10

Stephen M. Redd