ReadAllLines for a Stream object?

Solution 1:

You can write a method which reads line by line, like this:

public IEnumerable<string> ReadLines(Func<Stream> streamProvider,
                                     Encoding encoding)
{
    using (var stream = streamProvider())
    using (var reader = new StreamReader(stream, encoding))
    {
        string line;
        while ((line = reader.ReadLine()) != null)
        {
            yield return line;
        }
    }
}

Then call it as:

var lines = ReadLines(() => Assembly.GetExecutingAssembly()
                                    .GetManifestResourceStream(resourceName),
                      Encoding.UTF8)
                .ToList();

The Func<> part is to cope when reading more than once, and to avoid leaving streams open unnecessarily. You could easily wrap that code up in a method, of course.

If you don't need it all in memory at once, you don't even need the ToList...

Solution 2:

The .EndOfStream property can be used in the loop instead of checking if the next line is not null.

List<string> lines = new List<string>();

using (StreamReader reader = new StreamReader("example.txt"))
{
    while(!reader.EndOfStream)
    {
        lines.Add(reader.ReadLine());
    }
}

Solution 3:

using (Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("Test_Resources.Resources.Accounts.txt"))
using (StreamReader reader = new StreamReader(stream))
{
    // Would prefer string[] result = reader.ReadAllLines();
    string[] result = reader.ReadToEnd().Split(Environment.NewLine.ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
}

Solution 4:

The use of Split here:

reader
   .ReadToEnd()
   .Split(Environment.NewLine.ToCharArray(), StringSplitOptions.RemoveEmptyEntries);

is not equivalent to ReadLine. If you look at the source for ReadLine, StreamReader.cs, you will see that it handles line terminators: \r, \n, and \r\n correctly. ReadLine does not return an extra empty string when the line terminator is \r\n, which is typical in DOS/Windows. Split "sees" (parses) \r followed by \n as 2 separate delimiters and returns an empty string.

'StringSplitOptions.RemoveEmptyEntries' in the above code does remove these empty strings, but it will also remove any empty lines which appear in the input as well.

Thus for the input line1\r \r line3\r ReadLine returns 3 lines. The 2nd is empty. Split creates 4 strings. (There is an additional string after the last \r.) It then removes the 2nd and the 4th.

Note that Split is not well suited to parsing text lines which are "post-fix" delimited. That is the delimiter appears after the token. While Split is suitable for infix, where the delimiters appear between the tokens. It is the difference between a,b,c and line1\r,line2,line3\r. For these inputs, Split returns 3 strings or 4 strings respectively.

Solution 5:

Using the following extension method:

public static class Extensions
{
    public static IEnumerable<string> ReadAllLines(this StreamReader reader)
    {
        string line;
        while ((line = reader.ReadLine()) != null)
        {
            yield return line;
        }
    }
}

It's possible to get to your desired code:

using (Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("Test_Resources.Resources.Accounts.txt"))
using (StreamReader reader = new StreamReader(stream))
{
    string[] result = reader.ReadAllLines().ToArray();
}