File.ReadLines(filePath).First() 是否立即关闭文件?

Does File.ReadLines(filePath).First() close the file immediately?

我知道在 foreach 循环中使用 File.ReadLines() 返回的 IEnumerable 时,文件会在循环后自动关闭。 我只需要快速检查文件的第一行。这足够了还是会保持文件打开?

protected void Append(string filePath, Encoding encoding)
{
    try
    {
        string firstLine = File.ReadLines(filePath, encoding).First();
        // more code here
    }
    catch
    {
        // more code here
    }
}

(请注意,这是针对 File.ReadLines() 其中 returns 和 IEnumerable<String> - 这不适用于 File.ReadAllLines() 其中 returns String[].)


Does File.ReadLines(filePath).First() close the file immediately?

...假设“立即”是指 整个语句 完成时 - 而不仅仅是内部 ReadLines() 子表达式。


  • 在内部,File.ReadLines() returns 一个 instance of ReadLinesIterator - 这是一个 IEnumerable<T>.
  • 当迭代 IEnumerable<T> 时,C#/.NET 使用 IEnumerable<T>.GetEnumerator<T>() 其中 returns 和 IEnumerator<T> 其中 必须 在程序完成它想要的迭代后被释放。
    • 因为 IEnumerator<T> 个实例 必须 被处置,所以我们总是鼓励您使用 foreach 来为您处理这个问题(而不是手动处理 IEnumerator<T> 你自己)。
      • foreach 还将确保 IEnumerator<T>foreach 循环体内抛出异常时被释放。
  • 在此特定情况下,ReadLinesIterator 包含一个 StreamReader(其中包含打开的 FileStream)。当 ReadLinesIterator 被处理时,内部 StreamReader 被关闭,这反过来又关闭了 FileStream.
  • .Frist() 方法是 Linq 的 Enumerable.First( IEnumerable<T> source )
    • 在内部,Linq 的 First() 与调用 foreach( T item in source ) 并立即在 foreach 内部返回相同的事情 - 因此 First 方法将为您处理 ReadLinesIterator .

安全

我注意到 ReadLinesIterator is both an IEnumerator<T> and an IEnumerable<T> 并且它包装了一个开放的 StreamReader - 这意味着您在使用 ReadLines() 时确实需要小心以确保IEnumerable<T> 你看到的实际上是迭代过的,否则你确实有泄漏打开文件句柄的风险。

...这也意味着,如果您正在使用 Linq 方法链,并且异常发生在 Linq 链内部 但在外部 Linq 的任何内部 try/catch /foreach/using 块然后你将泄漏一个文件句柄,该文件句柄在 GC 完成 ReadLinesIterator 之前不会关闭......尽管我承认我很难想到什么时候可以发生了。

File.ReadLinesreturnsIEnumerable<string>。 Enumerable使用IEnumerator<string>读取行,这是一次性的。

阅读第一行并确保资源安全的正确方法:

var lines = File.ReadLines(path);
string firstLine;
using (var it = lines.GetEnumerator())
{
    if (!it.MoveNext())
        throw new InvalidOperationException("File is empty");
    firstLine = it.Current;
}

UseLine(firstLine);

这很复杂,但肯定是安全的

使用流 reader.

读取文件的最佳实践 ID
var lines = new List<string>();

using (StreamReader reader = new StreamReader(@"C:\test.txt")) {
    var line = reader.ReadLine();

    while (line != null) {
        lines.Add(line);
        line = reader.ReadLine();
    }
}

一旦代码移出 using 语句,fill 对象将被释放,wfile 将被关闭。 File.ReadLines 从不关闭文件。