Stream对象的ReadAllLines?

Rya*_*hel 55 c# text file stream

存在File.ReadAllLines但不存在Stream.ReadAllLines.

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();
}
Run Code Online (Sandbox Code Playgroud)

有没有办法做到这一点,还是我必须逐行手动循环文件?

Jon*_*eet 96

你可以编写一个逐行读取的方法,如下所示:

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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

然后将其称为:

var lines = ReadLines(() => Assembly.GetExecutingAssembly()
                                    .GetManifestResourceStream(resourceName),
                      Encoding.UTF8)
                .ToList();
Run Code Online (Sandbox Code Playgroud)

Func<>部分是在不止一次阅读时应对,并避免不必要地打开流.当然,您可以轻松地将该代码包装在一个方法中.

如果你不需要一次在内存中,你甚至不需要ToList......

  • @CodeBlend:不,当ReadLine到达流的末尾时,它返回null。 (2认同)
  • @Brondahl:是的,有一个好处:在尝试读取流之前,您可能不知道流是否已结束。可能不会有更多数据出现,而这才是您真正关心的。(这里的编辑是不合适的 - 编辑不应该改变意图,而这肯定会做到这一点。)(我怀疑在某些情况下 `StreamReader.EndOfStream` 基本上会在这里给出错误的结果,但我'我现在不会花时间来证明这一点。) (2认同)
  • @JonSkeet我认为这涉及到我从来没有真正需要理解的Streams部分,因为我只将它们与文件或WebRequests一起使用。如果我没理解错的话,那么你是说有一些方法可以将数据加载到 Stream 中,这样 `.EndOfStream` 可以返回 `false`,但调用 `.ReadLine()` 仍然会返回 `null`。是对的吗?相反的情况也可能吗?`.EndOfStream` 可以返回 `true`,但是调用 `.ReadLine()` 会返回实际数据? (2认同)

小智 36

.EndOfStream属性可以在循环中使用,而不是检查下一行是否为空.

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

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


Ste*_*ner 6

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);
}
Run Code Online (Sandbox Code Playgroud)


And*_*son 6

使用在Split这里:

reader
   .ReadToEnd()
   .Split(Environment.NewLine.ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
Run Code Online (Sandbox Code Playgroud)

不等于ReadLine.如果你看一下源ReadLine,StreamReader.cs,你会看到,它处理行结束符:\ r \n和\ r \n正确.ReadLine当行终止符是\ r \n时,不会返回额外的空字符串,这在DOS/Windows中是典型的.Split"see"(解析)\ r后跟\n作为2个单独的分隔符并返回一个空字符串.

上面代码中的'StringSplitOptions.RemoveEmptyEntries'确实删除了这些空字符串,但它也会删除输入中出现的所有空行.

因此,对于输入line1\r\r \n,line3\r \n ReadLine返回3行.第二个是空的. Split创建4个字符串.(最后一个\ r \n后面还有一个字符串.)然后删除第二个和第四个字符串.

请注意,Split它不适合解析"后修复"分隔的文本行.这是在令牌之后出现的分隔符.虽然Split适用于中缀,但分隔符出现在令牌之间.它是a,b,c和line1\r \n,line2,line3\r \n之间的差异.对于这些输入,分别Split返回3个字符串或4个字符串.


Fid*_*del 6

使用以下扩展方法:

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

可以得到您想要的代码:

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