统计文本文件行数

这么个简单问题,居然在网上找不到现成的代码。只好自己做了。

1、TStringList 法:

function GetTextLineCount_SL(const strFileName: string): UInt64;
begin
  with TStringList.Create do
  begin
    LoadFromFile(strFileName);
    Result := Count;
    Free;
  end;
end;

这种方案,只能针对小文件,大文件就不行了。
既然是文本文件,那么可以使用 readln 方法来读取试试。

2、TextFile 法:

function GetTextLineCount_TF(const strFileName: string): UInt64;
var
  F: TextFile;
begin
  Result := 0;
  AssignFile(F, strFileName);
  SetTextBuf(F, Buffer);
  Reset(F);
  while not eof(F) do
  begin
    Readln(F);
    Inc(Result);
  end;
  CloseFile(F);
end;

这种方案。有个缺陷:它返回的行数和 TStringlist 法返回的行数是不一样的。
原因:TStringlist 法,#13#10 当成换行,#13、#10也会被当成换行进行计数(具体可以参看 Delphi 源码)。而 readln 则不会。
看来针对大文件,还得另想它法。
试试文件流的方式。

3、FileStream 法(Linux 下,只用 #10 作为换行符,而 Windows 下,#13#10、#13、#10,都可作为换行符):

function GetTextLineCount_FS(const strFileName: string; const bLinux: Boolean = False): UInt64;
var
  FS      : TFileStream;
  I, Count: Integer;
  startPos: Integer;
  partXPos: Integer;
begin
  Result   := 0;
  startPos := 0;
  partXPos := 0;
  FS       := TFileStream.Create(strFileName, fmOpenRead);
  try
    Count := FS.Size;
    if bLinux then
    begin
      while FS.Position < Count do
      begin
        FS.Read(Buffer[0], c_intLength);
        startPos := startPos + c_intLength;
        if startPos > Count then
          partXPos := startPos - Count;

        for I := 0 to c_intLength - 1 - partXPos do
        begin
          if (Buffer[I] = #10) then
            Inc(Result);
        end;
      end;
    end
    else
    begin
      while FS.Position < Count do
      begin
        FS.Read(Buffer[0], c_intLength);
        startPos := startPos + c_intLength;
        if startPos > Count then
          partXPos := startPos - Count;

        for I := 0 to c_intLength - 1 - partXPos do
        begin
          if (Buffer[I] = #13) and (Buffer[I + 1] = #10) then
            Inc(Result)
          else if (Buffer[I] = #13) and (Buffer[I + 1] <> #10) then
            Inc(Result)
          else if (Buffer[I] <> #13) and (Buffer[I + 1] = #10) then
            Inc(Result);
        end;
      end;
    end;
  finally
    FS.Free;
  end;
end;

测试:(函数名、行数、耗时)
30M  文本文件:
  GetTextLineCount_SL  828125   987毫秒
  GetTextLineCount_TF  828092   484毫秒
  GetTextLineCount_FS  828125     96毫秒

600M 文本文件:
  GetTextLineCount_SL   <         不支持        >
  GetTextLineCount_TF  14177571   8758毫秒
  GetTextLineCount_FS  14181548   1659毫秒(Linux 829毫秒)


第三种方案最好,即兼容第一种,又比第一种效率高出 10 倍左右。

源码:GitHub - dbyoung720/TextLineCount: Text Line Count

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值