计算文本文件中的行数是否有任何技巧?

xyz*_*xyz 8 .net c# windows text text-files

假设您有一个文本文件 - 确定该文件中文本行数的最快和/或最有效的内存方式是什么?

是否只是逐个字符地扫描它并寻找换行符?

Mat*_*ted 11

可能不是最快的,但它将是最多才多艺的......

int lines = 0;
/* if you need to use an encoding other than UTF-8 you way want to try...
   new StreamReader("filename.txt", yourEncoding) 
   ... instead of File.OpenText("myFile.txt")
*/
using (var fs = File.OpenText("myFile.txt"))
    while (!fs.EndOfStream)
    {
        fs.ReadLine();
        lines++;
    }
Run Code Online (Sandbox Code Playgroud)

......这可能会更快......

如果您需要更高的速度,您可以尝试Duff的设备并在分支前检查10或20个字节

int lines = 0;
var buffer = new byte[32768];
var bufferLen = 1;    
using (var fs = File.OpenRead("filename.txt"))
    while (bufferLen > 0)
    {
        bufferLen = fs.Read(buffer, 0, 32768);
        for (int i = 0; i < bufferLen; i++)
            /* this is only known to work for UTF-8/ASCII other 
               file types may need to search for different End Of Line 
               characters */                
            if (buffer[i] == 10)           
                lines++;
    }
Run Code Online (Sandbox Code Playgroud)

  • 我认为Matthew的观点是你可以将东西加载到缓冲区中以节省内存.不是计算换行符的方法. (2认同)

Jon*_*eet 10

除非你有一个固定的行长度(以字节单位),否则你肯定需要读取数据.是否可以避免将所有数据转换为文本将取决于编码.

现在最有效的方法是重新加载 - 手动计算行结束.但是,最简单的代码是使用TextReader.ReadLine().实际上,最简单的方法是使用MiscUtil中的LineReader类,它将文件名(或其他各种东西)转换为.然后你可以使用LINQ:IEnumerable<string>

int lines = new LineReader(filename).Count();
Run Code Online (Sandbox Code Playgroud)

(如果你不想获取整个MiscUtil,你可以LineReader这个答案中获得它自己.)

现在这会产生大量的垃圾,反复读入相同的char数组也不会 - 但它一次不会读取多行,所以虽然你会对GC有点压力,但它不会炸毁大文件.它还需要将所有数据解码为文本 - 您可以在不进行某些编码的情况下将其丢弃.

就个人而言,这是我使用的代码,直到我发现它导致了瓶颈 - 它比手动操作要简单得多.你是否完全知道在你目前的情况下,上面的代码会成为瓶颈?

与以往一样,不要微观优化,直到你必须...而且你可以在以后很容易地优化它而不改变你的整体设计,所以推迟它不会造成任何伤害.

编辑:将马修的答案转换为适用于任何编码的答案 - 但这将导致解码所有数据的惩罚,当然,您可能会得到类似下面的代码.我假设你关心\n-而不是\r,\n并且\r\nTextReader通常用于处理:

public static int CountLines(string file, Encoding encoding)
{
    using (TextReader reader = new StreamReader(file, encoding))
    {
        return CountLines(reader);
    }
}

public static int CountLines(TextReader reader)
{
    char[] buffer = new char[32768];

    int charsRead;
    int count = 0;

    while ((charsRead = reader.Read(buffer, 0, buffer.Length)) > 0)
    {
        for (int i = 0; i < charsRead; i++)
        {
            if (buffer[i] == '\n')
            {
                count++;
            }
        }
    }
    return count;
}
Run Code Online (Sandbox Code Playgroud)

  • 它不会是最快的方式,不是.但是,它可以很容易地使用你抛出的任何编码,并且很容易做到.那些*通常比在我的经验中获得绝对最快的代码更重要.在我得到最好的证据表明最简单的方法太慢之后,我才开始进行微观优化. (2认同)

TLi*_*ebe 5

如果它是固定记录,您可以获取记录的大小,然后将总文件大小除以该数量以获得记录数.如果您只是在寻找估计值,那么我过去所做的只是读取前x行(例如200行)并使用它来得出平均行大小,然后您可以使用它来猜测总数记录(将文件总大小除以平均行大小).如果您的记录相当统一并且您不需要精确计数,则此方法很有效.我在大文件上使用了这个(快速检查以获取文件大小,如果它超过20 MB然后得到估计而不是读取整个文件).

除此之外,唯一100%准确的方法是使用ReadLine逐行浏览文件.