I have a LineReader class in my MiscUtil project. It is a little more general than the solutions proposed here, mainly in terms of how to create it:
- From a function that returns a stream, in which case it will use UTF-8
- From stream return function and encoding
- From a function that returns a text reader
- On behalf of the file, in this case it will use UTF-8
- On behalf of the file and encoding
The class "owns" any resources that it uses and closes them accordingly. However, he does this without implementing IDisposable . That is why instead of a stream or a reader, he takes Func<Stream> and Func<TextReader> - he should be able to postpone the hole until he needs it. This is the iterator itself (which is automatically located in the foreach ), which closes the resource.
As Mark noted, this works well in LINQ. One example I would like to give:
var errors = from file in Directory.GetFiles(logDirectory, "*.log") from line in new LineReader(file) select new LogEntry(line) into entry where entry.Severity == Severity.Error select entry;
This will cause all errors to flow from a number of log files, opening and closing as they occur. In combination with Push LINQ you can do all kinds of nice things :)
This is not a particularly "complicated" class, but it is really convenient. Here is the full source, for convenience, if you do not want to download MiscUtil. Source code license here .
using System; using System.Collections; using System.Collections.Generic; using System.IO; using System.Text; namespace MiscUtil.IO { /// <summary> /// Reads a data source line by line. The source can be a file, a stream, /// or a text reader. In any case, the source is only opened when the /// enumerator is fetched, and is closed when the iterator is disposed. /// </summary> public sealed class LineReader : IEnumerable<string> { /// <summary> /// Means of creating a TextReader to read from. /// </summary> readonly Func<TextReader> dataSource; /// <summary> /// Creates a LineReader from a stream source. The delegate is only /// called when the enumerator is fetched. UTF-8 is used to decode /// the stream into text. /// </summary> /// <param name="streamSource">Data source</param> public LineReader(Func<Stream> streamSource) : this(streamSource, Encoding.UTF8) { } /// <summary> /// Creates a LineReader from a stream source. The delegate is only /// called when the enumerator is fetched. /// </summary> /// <param name="streamSource">Data source</param> /// <param name="encoding">Encoding to use to decode the stream /// into text</param> public LineReader(Func<Stream> streamSource, Encoding encoding) : this(() => new StreamReader(streamSource(), encoding)) { } /// <summary> /// Creates a LineReader from a filename. The file is only opened /// (or even checked for existence) when the enumerator is fetched. /// UTF8 is used to decode the file into text. /// </summary> /// <param name="filename">File to read from</param> public LineReader(string filename) : this(filename, Encoding.UTF8) { } /// <summary> /// Creates a LineReader from a filename. The file is only opened /// (or even checked for existence) when the enumerator is fetched. /// </summary> /// <param name="filename">File to read from</param> /// <param name="encoding">Encoding to use to decode the file /// into text</param> public LineReader(string filename, Encoding encoding) : this(() => new StreamReader(filename, encoding)) { } /// <summary> /// Creates a LineReader from a TextReader source. The delegate /// is only called when the enumerator is fetched /// </summary> /// <param name="dataSource">Data source</param> public LineReader(Func<TextReader> dataSource) { this.dataSource = dataSource; } /// <summary> /// Enumerates the data source line by line. /// </summary> public IEnumerator<string> GetEnumerator() { using (TextReader reader = dataSource()) { string line; while ((line = reader.ReadLine()) != null) { yield return line; } } } /// <summary> /// Enumerates the data source line by line. /// </summary> IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } } }
Jon Skeet Nov 13 '08 at 9:13 2008-11-13 09:13
source share