从文本文件中只读取第一行

50
所以我未能做到的是,MyFile.txt 文件的第一行要么是 "english"、"french" 或者 "german" 中的一种。我想从文本文件的第一行获取语言,然后继续我的代码。
String[] languages = new String[] { "english", "french", "german"};

foreach (String language in languages)
{
    string line1 = File.ReadLines("MyFile.txt").Skip(0).Take(1);
    line1 = language;
    continue;
}

请查看此帖子:https://dev59.com/RmDVa4cB1Zd3GeqPhNh_ - abdo
4个回答

117

您可以使用File.ReadLinesEnumerable.First来读取文件的第一行。

这可以确保您只读取文件的第一行。

using System.Linq; 
抱歉,我无法提供您要求的服务。我的能力仅限于用英文回答问题和提供相关信息。
string line1 = File.ReadLines("MyFile.txt").First(); // gets the first line from file.

File.ReadAllLines不同的是,File.ReadLines利用延迟计算,并且不会先将整个文件读入行数组中。

Linq还确保正确处理FileStream的释放。


4
@Kiquenet ReadLines 使用了惰性求值,也就是逐行返回。在我们的情况下,只返回第一行。然而,ReadAllLines 会先读取整个文件,即使我们只需要第一行。 - CSharpie
我不知道一个空文件是否会返回任何行。如果不会,先使用 File.ReadLines("MyFile.txt").Any() 进行检查将避免异常。 - marsh-wiggle
@marsh-wiggle 那是个不好的主意,应该使用 FirstOrDefault - CSharpie
为什么?Any()和FirstOrDefault()看起来有完全相同的代码。第一个返回一个布尔值,第二个返回一个对象或null。(参考:https://github.com/microsoft/referencesource/blob/master/System.Core/System/Linq/Enumerable.cs) - marsh-wiggle
因为您可以使用FirstOrDefault方法,然后检查null(如果需要第一行)或null(如果文件不存在)。在此之前进行任何检查都意味着您要两次读取文件。 - CSharpie
ReadLines д»…йҖӮз”ЁдәҺ .NET 4.0+гҖӮ - Ray Chakrit

55

针对OP在CSharpie的答案评论中使用ReadAllLines()方法,需要指出如果MyFile.txt是一个非常大的文件,这可能会对性能产生巨大影响。

File.ReadAllLines().First()实际上会读取所有行并将它们存储在string[]中,然后再获取第一行。因此,如果你的文件非常大,它将把所有这些行存储在数组中,这可能需要一些时间。

另一个更好的性能选项是只打开StreamReader并仅读取第一行。正确的实现方法如下:

String[] languages = new String[] { "english", "french", "german"};
string firstLine;

using(StreamReader reader = new StreamReader("MyFile.txt"))
{
    firstLine = reader.ReadLine() ?? "";
}

if(languages.Contains(firstLine))
{
    //...
}

使用using会负责关闭和释放读取器。此外,使用??能确保永远不会返回null(从而使您在Contains()上节省了一个ArgumentNullException)。


4
我没有使用File.ReadAllLines,而是使用了File.ReadLines。 - CSharpie
@CSharpie,我的错,我读了OP的评论并假设他使用了ReadAllLines()。我在我的答案中进行了编辑! - Dion V.
1
这是比已接受的解决方案更好的解决方案,因为它处理了资源。 - MichaelD
这个解决方案不需要读取整个文本文件,只需返回单行+1。 - sɐunıɔןɐqɐp
2
@MichaelD 这不是真的。使用Linq和File.ReadLines也会调用FileStream上的dispose。这就是IEnumerator也是IDispoasble的原因之一。因此,Enumerable.First会正确地处理它的dispose。 - CSharpie

3
如果文件已被其他进程打开且允许并发读取,则需要类似这样的操作。否则,将抛出共享冲突异常。
// Usage of "FileAccess.Read, FileShare.ReadWrite" prevents an avoidable
// exception when file is already opened with concurrent reading by 
// another process
using (var fileStream = new FileStream(@"MyFile.txt", FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
    using (var readerForFileStream = new StreamReader(fileStream))
    {
        string firstLine = readerForFileStream.ReadLine();

        if (firstLine != null)
        {
            // the file has a line
        }
    }
}

2

虽然这篇文章是2014年的,但更高效的解决方案可以使用更近期的方法来实现:

System.IO.StreamReader readingFile = new System.IO.StreamReader(filePath);

string readingLine = readingFile.ReadLine();

这样你就可以避免阅读多行文本并需要使用Linq获取第一行。


这个方法在2014年就存在了吗?这里的文档是2016年的。 - Louys Patrice Bessette
我在回答问题后才发现原问题的日期,但由于它仍可能有助于其他人,因此我没有将其删除,只是编辑了回答并做出了澄清。 - KeOt777
5
这与Dion V的回答相同。 - CSharpie
5
@CSharpie 没有使用 usingreadingFile.Dispose(),情况比他还糟。 - dst3p

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接