确定文本文件中的行数

Determine the number of lines within a text file

提问人:TK. 提问时间:9/23/2008 最后编辑:H.B.TK. 更新时间:6/14/2023 访问量:315938

问:

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

C# 输入 文本文件

评论


答:

443赞 Greg Beech 9/23/2008 #1

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

该类有一个新的 ReadLines 方法,它懒惰地枚举行,而不是贪婪地将它们全部读入一个数组中,如 。因此,现在您可以通过以下方式既高效又简洁:FileReadAllLines

var lineCount = File.ReadLines(@"C:\file.txt").Count();

原始答案

如果你不太在意效率,你可以简单地写:

var lineCount = File.ReadAllLines(@"C:\file.txt").Length;

为了获得更有效的方法,您可以执行以下操作:

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

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

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

就速度而言,我不会指望它有很多。ReadAllLines 可能有一些内部优化,但另一方面,它可能必须分配大量内存。我猜 ReadAllLines 对于小文件可能更快,但对于大文件来说要慢得多;尽管唯一的判断方法是使用秒表或代码分析器进行测量。

评论

2赞 Mike Dimmick 9/23/2008
小注意:因为 String 是一个引用类型,所以数组将是行数的大小 x 指针的大小,但你是对的,它仍然需要存储文本,每行都是一个 String 对象。
16赞 Owen Allen 5/24/2013
仅供参考:为了做到这一点,您需要在包含中添加一个。要求添加该内容似乎相当不直观,因此这就是我提到它的原因。如果你使用的是 Visual Studio,则此添加很可能是自动为你完成的。ReadLines().Count()using System.Linq
2赞 Yogee 3/12/2014
我已经测试了这两种方法,“File.ReadLines.Count()”与“reader”。ReadLine()“和”reader.ReadLine()“稍微快一点,但速度快得很少。“ReadAllLines”比较松散,需要双倍的时间并占用大量内存)。这是因为“File.ReadLines.Count()”和“reader.ReadLine()“是一个枚举器,它逐行读取文件,并且不会将整个文件加载到内存中,而是再次在RAM中读取它。
13赞 Greg Beech 5/12/2016
是的,没有人使用过 4GB+ 的文件。我们当然从不处理这么大的日志文件。哦,等等。
4赞 Steve Kinyon 5/13/2016
如果您想查看 File.ReadLines() 的内部内容,请转到此处:System.IO.File.cs当您向下钻取重载时,它会将您带到此处:ReadLinesIterator.cs
2赞 Mitchel Sellers 9/23/2008 #2

您可以快速读取它,并递增计数器,只需使用循环递增,对文本不执行任何操作。

评论

3赞 IamBatman 3/1/2017
这应该是一个评论,而不是一个答案。
13赞 leppie 9/23/2008 #3

最简单的:

int lines = File.ReadAllLines("myfile").Length;
1赞 geocoin 9/23/2008 #4

计算回车/换行次数。我相信在 unicode 中,它们仍然分别是 0x000D 和 0x000A。这样一来,你就可以随心所欲地提高效率或效率低下,并决定是否必须同时处理这两个角色

5赞 user8456 9/23/2008 #5

如果你说的简单是指一行容易破译但效率低下的代码?

string[] lines = System.IO.File.RealAllLines($filename);
int cnt = lines.Count();

这可能是知道有多少行的最快方法。

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

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

还有其他许多方法,但上述方法之一可能是您会选择的。

评论

4赞 Mike Christian 6/1/2012
我认为这种方法效率非常低下;因为,你正在将整个文件读入内存和字符串数组,同样如此。使用 ReadLine 时,无需复制缓冲区。请看@GregBeech的答案。对不起,在你的游行中下雨。
8赞 benPearce 9/23/2008 #6

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

int count = 0;
string line;
TextReader reader = new StreamReader("file.txt");
while ((line = reader.ReadLine()) != null)
{
  count++;
}
reader.Close();
-4赞 Sklivvz 9/23/2008 #7

您可以启动作为外部进程运行的“wc.exe”可执行文件(自带UnixUtils,不需要安装)。它支持不同的行数方法(如 unix vs mac 和 windows)。

评论

1赞 Krythic 5/20/2016
这不可能足够快而有用。仅调用可执行文件的开销将是单个递增循环的两倍(明显的夸张是显而易见的)。
-1赞 Muhammad Usman -kai hiwatari 10/7/2012 #8
try {
    string path = args[0];
    FileStream fh = new FileStream(path, FileMode.Open, FileAccess.Read);
    int i;
    string s = "";
    while ((i = fh.ReadByte()) != -1)
        s = s + (char)i;

    //its for reading number of paragraphs
    int count = 0;
    for (int j = 0; j < s.Length - 1; j++) {
            if (s.Substring(j, 1) == "\n")
                count++;
    }

    Console.WriteLine("The total searches were :" + count);

    fh.Close();

} catch(Exception ex) {
    Console.WriteLine(ex.Message);
}         

评论

5赞 ya23 9/12/2013
-1:这将很慢,消耗大量内存并给 GC 带来困难!
1赞 Krythic 5/20/2016 #9

一个可行的选项,也是我个人使用过的一个选项,是将您自己的标题添加到文件的第一行。我这样做是为了我的游戏的自定义模型格式。基本上,我有一个工具可以优化我的.obj文件,去掉我不需要的废话,将它们转换为更好的布局,然后在第一行写下线条、面、法线、顶点和纹理 UV 的总数。然后,在加载模型时,各种数组缓冲区使用该数据。

这也很有用,因为您只需要遍历文件一次即可将其加载,而不是一次来计算行数,然后再次将数据读取到创建的缓冲区中。

6赞 Walter Verhoeven 5/24/2018 #10

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

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

尼玛·阿拉(Nima Ara)做了一个很好的分析,您可以考虑

这是建议的解决方案,因为它一次读取 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;
}

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

如果你把它描述为完成海湾尼玛,你会发现这是一种相当快速和有效的方法。

0赞 Khalil Youssefi 8/9/2020 #11

使用这个:

    int get_lines(string file)
    {
        var lineCount = 0;
        using (var stream = new StreamReader(file))
        {
            while (stream.ReadLine() != null)
            {
                lineCount++;
            }
        }
        return lineCount;
    }
0赞 pbies 6/13/2023 #12

选定的答案对我来说没问题,但我需要更改为大型文本文件,因此代码如下所示:varlong

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

在其他情况下,int 会从破坏计数的负值中环绕出来。

此外,我正在考虑计算文件中换行符 (LF) 数的解决方案 - 按 1 MB 或 100 MB 读取二进制文件(取决于内存),而不是通过 C# 函数逐行读取。

编辑:

我写了这段代码:

var sr = new StreamReader(file);
int rb = 100 * 1024 * 1024;
char[] buf = new char[rb];
int lf = 0;
int taken = 0;
while ((taken = sr.ReadBlock(buf, 0, rb)) != 0)
{
    lf += buf.Take(taken).Count(x => x == '\x0a');
}

好像不是更快......