需要帮助理解微软对文件的解释.ReadLines和File.ReadAllLines



根据Microsoft对ReadLinesReadAllLines方法的解释,当您使用ReadLines时,您可以在返回整个集合之前开始枚举字符串集合。当您使用ReadAllLines时,您必须等待整个字符串数组返回,然后才能访问该数组。因此,当您处理非常大的文件时,ReadLines可以更有效。

当他们说:

1 - "当你使用ReadLines时,你可以在返回整个集合之前开始枚举字符串集合。"如果写了下面这行代码,那么这是否意味着ReadLines方法的执行结束了,并且返回了整个集合&存储在可变的文件数据?

IEnumerable<String> filedata = File.ReadLines(fileWithPath)

2 - "当你使用ReadAllLines你必须等待整个字符串数组返回之前,你可以访问数组"。这是否意味着,在下面的代码片段中,如果读取一个大文件,那么如果在读取文件后立即使用数组变量hugeFileData,则不会拥有所有数据?

string[] hugeFileData = File.ReadAllLines(path)
string i = hugeFileData[hugeFileData.length-1];

3 - "当你处理非常大的文件时,ReadLines可以更有效"。如果是这样的话,下面的代码在读取大文件时是否有效?我相信下面代码的第2行和第3行会读取文件两次,如果我错了请纠正我。

string fileWithPath = "some large sized file path";
string lastLine = File.ReadLines(fileWithPath).Last();
int totalLines = File.ReadLines(fileWithPath).Count();

在上面的代码片段中对同一个文件调用两次ReadLines的原因是,当我尝试下面的代码时,我在下面的代码片段的第3行得到了一个异常"Cannot read from a closed TextReader "。

IEnumerable<String> filedata = File.ReadLines(fileWithPath);
string lastLine = filedata.Last();
int totalLines = filedata.Count();

ReadLinesReadAllLines的区别很容易用代码来说明。

如果你这样写:

foreach (var line in File.ReadLines(filename))
{
    Console.WriteLine(line);
}

发生的情况与下面类似:

using (var reader = new StreamReader(filename))
{
    while (!reader.EndOfStream)
    {
        var line = reader.ReadLine();
        Console.WriteLine(line);
    }
}

实际生成的代码稍微复杂一些(ReadLines返回一个枚举器,其MoveNext方法读取并返回每一行),但从外部看,行为是相似的。

这种行为的关键是延迟执行,为了更好地使用LINQ,你应该很好地理解它。所以你第一个问题的答案是否定的对ReadLines的所有调用只是打开文件并返回一个枚举数。它不会读取第一行,直到你要求它。

注意,代码可以在读取第二行之前输出第一行。另外,每次只使用一行的内存。

ReadAllLines有很多不同的行为。当你写:

foreach (var line in File.ReadAllLines(filename))
{
    Console.WriteLine(line);
}

实际情况是这样的:

List<string> lines = new List<string>();
using (var reader = new StreamReader(filename))
{
    while (!reader.EndOfStream)
    {
        var line = reader.ReadLine();
        lines.Add(line);
    }
}
foreach (var line in lines)
{
    Console.WriteLine(line);
}

在这里,程序必须在输出第一行之前将整个文件加载到内存中。

使用哪一个取决于你想做什么。如果您只需要逐行访问文件,那么ReadLines通常是更好的选择——特别是对于大文件。但是,如果您想随机访问行,或者如果您将多次读取文件,那么ReadAllLines可能更好。但是,请记住,ReadAllLines要求您有足够的内存来容纳整个文件。

在第三个问题中,您展示了这段代码,它在最后一行产生了一个异常:

IEnumerable<String> filedata = File.ReadLines(fileWithPath);
string lastLine = filedata.Last();
int totalLines = filedata.Count();

这里的情况是第一行返回一个枚举数。第二行代码枚举了整个序列(即读取到文件的末尾),以便找到最后一行。枚举器发现它位于文件末尾,于是关闭了关联的读取器。最后一行代码再次尝试枚举文件,但文件已经关闭。在ReadLines返回的枚举器中没有"重置到文件的开头"功能。

  1. 。在程序的这一点上,文件的零行需要从磁盘中读取并存储在内存中。直到您请求第一行(在该代码片段中您还没有请求过一行),它才需要获取第一行。直到你请求之后的行,它才需要获取第二行,以此类推。

  2. 该程序将要求将整个文件一次性读入内存,以便获取最后一行。如果你有一个3gb的文件,你需要3gb的内存

  3. 是的,第一个代码片段将读取整个文件两次,不需要在任何时间点在内存中存储多行。该程序的内存占用将是0(1),而不是依赖于程序的大小。它确实需要读取整个程序的开始到结束两次,所以它可能需要更长的时间来执行,但它将消耗远远小于您在它之前展示的代码片段。当然,有一些方法可以使用ReadLines来计算行数并获取最后一行,而不需要对序列进行两次迭代,这是您真正应该做的,这样您就可以获得两全其美的效果。

ReadLines()方法使用枚举器只在需要时读取每行,因此这样的代码可以工作,因为该方法根据需要获取每行:

foreach (string line in File.ReadLines("c:\file.txt"))
{
    Console.WriteLine("-- {0}", line);
}

如果文件很大,ReadLines()方法很有用,因为它不需要一次将所有数据保存在内存中。此外,如果您的程序提前退出循环,ReadLines()会更好,因为不需要进一步的I/O。

ReadAllLines()方法将整个文件读入内存,然后返回这些行组成的数组。

  1. 是的,这个方法是完成执行的。不,执行还没有结束。返回的可枚举对象包含从文件中读取的所有必要的数据和行为,并将行交给您。
  2. File.ReadAllLines完成时,整个文件已被读取。字符串[]不能惰性返回结果。因此,从类型中您可以看到File.ReadAllLines急切地执行所有工作。
  3. 是的,你读了两次文件。这并不一定是这样的。用循环遍历返回的行,维护一个计数器和看到的最后一行。这允许您在一次遍历文件时计算两个值。

你可以这样使用ReadLines:

foreach (string line in File.ReadLines(fileWithPath))
{
    if (line.Contains("bla bla") & line.Contains("do do"))
    {
    }
    totalLines += 1;
}

在访问数组之前,您没有等待整个字符串数组返回。不像在继续之前加载整个数组:

string[] readText = File.ReadAllLines(path);
foreach (string s in readText)
{
    Console.WriteLine(s);
}

相关内容

  • 没有找到相关文章

最新更新