确定文本文件中的行数

TK.*_*TK. 198 c# input text-files

有一种简单的方法可以以编程方式确定文本文件中的行数吗?

Gre*_*ech 381

严重迟来的编辑:如果您使用的是.NET 4.0或更高版本

这个File类有一个新ReadLines方法,它懒洋洋地枚举行而不是贪婪地将它们全部读入数组中ReadAllLines.所以现在你可以同时兼顾效率和简洁:

var lineCount = File.ReadLines(@"C:\file.txt").Count();
Run Code Online (Sandbox Code Playgroud)

原始答案

如果你对效率不太感兴趣,你可以简单地写:

var lineCount = File.ReadAllLines(@"C:\file.txt").Length;
Run Code Online (Sandbox Code Playgroud)

要获得更有效的方法,您可以:

var lineCount = 0;
using (var reader = File.OpenText(@"C:\file.txt"))
{
    while (reader.ReadLine() != null)
    {
        lineCount++;
    }
}
Run Code Online (Sandbox Code Playgroud)

编辑:回答有关效率的问题

我说第二个更高效的原因是关于内存使用,不一定是速度.第一个将文件的全部内容加载到一个数组中,这意味着它必须分配至少与文件大小一样多的内存.第二个只是一次循环一行,所以它不必一次分配多行的内存.这对于小文件来说并不重要,但对于较大的文件,这可能是一个问题(例如,如果您尝试在32位系统上查找4GB文件中的行数,例如,根本不够用户模式地址空间来分配这么大的数组).

在速度方面,我不希望它有很多.ReadAllLines可能有一些内部优化,但另一方面它可能需要分配大量内存.我猜对于小文件,ReadAllLines可能更快,但对于大文件来说速度要慢得多; 虽然告诉的唯一方法是使用秒表或代码分析器来测量它.

  • 仅供参考:为了执行`ReadLines().Count()`,你需要在你的包中添加一个`using System.Linq`.要求添加似乎相当不直观,这就是我提到它的原因.如果您使用的是Visual Studio,则可能会自动为您完成此添加. (15认同)
  • 是的,没有人使用过4GB +的文件.我们当然从不处理那些大的日志文件.等一下. (9认同)
  • 小注意:因为String是一个引用类型,所以数组的大小是行数×指针大小的大小,但你仍然需要存储文本,每行作为一个String对象. (2认同)
  • 我已经测试了这两种方法,“File.ReadLines.Count()”v/s“reader.ReadLine()”和“reader.ReadLine()”稍微快一点,但它的速度相差很小。“ReadAllLines”更松散,需要两倍的时间并占用大量内存)。这是因为 "File.ReadLines.Count()" 和 "reader.ReadLine()" 是一个枚举器,它逐行读取文件并且不会将整个文件加载到内存中,然后再次在 RAM 中读取它。 (2认同)
  • 如果你想看到File.ReadLines()的内部,请访问:[System.IO.File.cs](http://referencesource.microsoft.com/#mscorlib/System/io/file.cs)当你钻通过重载,你需要在这里:[ReadLinesIterator.cs](http://referencesource.microsoft.com/#mscorlib/System/io/ReadLinesIterator.cs) (2认同)

lep*_*pie 12

最简单的:

int lines = File.ReadAllLines("myfile").Length;
Run Code Online (Sandbox Code Playgroud)


ben*_*rce 8

这将使用更少的内存,但可能需要更长的时间

int count = 0;
string line;
TextReader reader = new StreamReader("file.txt");
while ((line = reader.ReadLine()) != null)
{
  count++;
}
reader.Close();
Run Code Online (Sandbox Code Playgroud)


use*_*456 5

如果简单的话,你的意思是一行代码很容易破译但机会效率低下?

string[] lines = System.IO.File.RealAllLines($filename);
int cnt = lines.Count();
Run Code Online (Sandbox Code Playgroud)

这可能是了解多少行的最快捷方式.

你也可以这样做(取决于你是否在缓冲它)

#for large files
while (...reads into buffer){
string[] lines = Regex.Split(buffer,System.Enviorment.NewLine);
}
Run Code Online (Sandbox Code Playgroud)

还有其他许多方法,但上面的一个可能是你将要用的.

  • 我认为这种方法效率很低; 因为,你正在将整个文件读入内存,并进入字符串数组,不会少.使用ReadLine时,您不必复制缓冲区.请参阅@GregBeech的答案.对不起,你的游行会下雨. (3认同)

PPa*_*ann 5

读取文件本身需要一些时间,垃圾收集结果是另一个问题,因为您读取整个文件只是为了计算换行符,

在某些时候,有人将不得不读取文件中的字符,无论这是框架还是您的代码。这意味着您必须打开文件并将其读入内存,如果文件很大,这可能会成为一个问题,因为内存需要被垃圾回收。

尼玛阿拉做了一个很好的分析,你可能会考虑

这是建议的解决方案,因为它一次读取 4 个字符,计算换行符并再次使用相同的内存地址进行下一个字符比较。

private const char CR = '\r';  
private const char LF = '\n';  
private const char NULL = (char)0;

public static long CountLinesMaybe(Stream stream)  
{
    Ensure.NotNull(stream, nameof(stream));

    var lineCount = 0L;

    var byteBuffer = new byte[1024 * 1024];
    const int BytesAtTheTime = 4;
    var detectedEOL = NULL;
    var currentChar = NULL;

    int bytesRead;
    while ((bytesRead = stream.Read(byteBuffer, 0, byteBuffer.Length)) > 0)
    {
        var i = 0;
        for (; i <= bytesRead - BytesAtTheTime; i += BytesAtTheTime)
        {
            currentChar = (char)byteBuffer[i];

            if (detectedEOL != NULL)
            {
                if (currentChar == detectedEOL) { lineCount++; }

                currentChar = (char)byteBuffer[i + 1];
                if (currentChar == detectedEOL) { lineCount++; }

                currentChar = (char)byteBuffer[i + 2];
                if (currentChar == detectedEOL) { lineCount++; }

                currentChar = (char)byteBuffer[i + 3];
                if (currentChar == detectedEOL) { lineCount++; }
            }
            else
            {
                if (currentChar == LF || currentChar == CR)
                {
                    detectedEOL = currentChar;
                    lineCount++;
                }
                i -= BytesAtTheTime - 1;
            }
        }

        for (; i < bytesRead; i++)
        {
            currentChar = (char)byteBuffer[i];

            if (detectedEOL != NULL)
            {
                if (currentChar == detectedEOL) { lineCount++; }
            }
            else
            {
                if (currentChar == LF || currentChar == CR)
                {
                    detectedEOL = currentChar;
                    lineCount++;
                }
            }
        }
    }

    if (currentChar != LF && currentChar != CR && currentChar != NULL)
    {
        lineCount++;
    }
    return lineCount;
}
Run Code Online (Sandbox Code Playgroud)

在上面,您可以看到底层框架一次读取一个字符,因为您需要读取所有字符才能查看换行符。

如果您将其描述为 done bay Nima,您会发现这是一种相当快速和有效的方法。