快速掃描文字檔,統計行數,並返回每一行的索引位置(Delphi、C#)

來源:互聯網
上載者:User

由項目需要,需要掃描1200萬行的文字檔。經網友的指點與測試,發現C#與Delphi之間的差距並不大。不多說,列代碼測試:

下面是Delphi的代碼:

 

//遍曆檔案尋找斷行符號出現的次數
function ScanEnterFile(const FileName:string):TInt64Array;
var
  MyFile:TMemoryStream;//檔案記憶體
  rArray:TInt64Array;       //行索引結果集
  size,curIndex:int64;//檔案大小,當前流位置
  enterCount:int64;//斷行符號數量
  DoLoop:Boolean;//是否繼續迴圈
  pc: PChar;
  arrayCount:int64;//當前索引數組大小
  addStep:integer;//檢測到斷行符號字串時需要添加的步進
begin
  if fileName = '' then
    Exit;
  if not FileExists(fileName) then
    Exit;
  MyFile:=TMemoryStream.Create;//建立流
  MyFile.LoadFromFile(fileName);//把流入口映射到MyFile對象
  size:=MyFile.Size;
  pc:=MyFile.Memory; //把字元指標指向記憶體流
  curIndex:=RowLeast;
  DoLoop:=true;
  enterCount:=0;
  setlength(rArray,perArray);
  arrayCount:=perArray;
  enterCount:=0;
  rArray[enterCount]:=0;
  while DoLoop do
  begin
    addStep:=0;
    if (ord(pc[curIndex])=13) then
      addStep:=2;
    if (ord(pc[curIndex])=10) then
      addStep:=1;
    //處理有斷行符號的
    if (addStep<>0) then
    begin
      Application.ProcessMessages;
      //增加一行記錄
      inc(enterCount);
      //判斷是否需要增大數組
      if (enterCount mod perArray=0) then
      begin
        arrayCount:=arrayCount+perArray;
        setlength(rArray,arrayCount);
      end;
      rArray[enterCount]:=curIndex+addStep;
      curIndex:=curIndex+addStep+RowLeast;
    end
    else
      curIndex:=curIndex+2;
    if curIndex> size then
      DoLoop:=false
    else
      DoLoop:=true;
  end;
  result:=rArray;
  freeandnil(MyFile);
end;

執行代碼:

 

procedure TMainForm.btn2Click(Sender: TObject);
var
  datasIndex:TInt64Array;//資料檔案索引
begin

  t1:=GetTickCount;
  datasIndex:=ScanEnterFile('R:\201201_dataFile.txt');
  Caption:=Caption+'::'+inttostr(GetTickCount-t1); 
end;

執行結果是:16782 ms

 

下面是C#的代碼:

 

        /// <summary>
        /// 掃描文字檔,進行行數的統計,並返回每一行的開始指標數組(1.2KW資料速度比使用數組的快10秒)
        /// </summary>
        /// <param name="fileName">檔案名稱</param>
        /// <param name="rowCount">行數</param>
        /// <param name="rowLeast">一行最小長度</param>
        /// <param name="incCount">遞增索引數組數量</param>
        /// <param name="initCount">首次初始化行索引數量</param>
        /// <returns>索引列表</returns>
        public static IList<long> ScanEnterFile(string fileName, out int rowCount, int rowLeast,ThreadProgress progress)
        {
            rowCount = 0;
            if (string.IsNullOrEmpty(fileName))
                return null;
            if (!System.IO.File.Exists(fileName))
                return null;
            FileStream myFile = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read, 8);//把檔案讀入流
            IList<long> rList=new List<long>();
            int enterCount = 0;//斷行符號數量
            int checkValue;
            int addStep;
            myFile.Position = rowLeast;
            checkValue = myFile.ReadByte();
            while (checkValue != -1)
            {
                //Application.DoEvents();
                addStep = -1;
                //由於檔案ReadByte之後,其當前位置已經往後推移了移位。
                //因此,如果是斷行符號的第一個字元,則要推移一位。
                //而如果是斷行符號的第二個字元,則不用推移一位
                if (checkValue == 13)
                    addStep = 1;
                else if (checkValue == 10)
                    addStep = 0;
                if (addStep >= 0)
                {
                    enterCount++;
                    rList.Add(myFile.Position + addStep);
                    myFile.Seek(rowLeast + addStep, SeekOrigin.Current);
                    progress(enterCount);
                }
                else myFile.Seek(2, SeekOrigin.Current);
                checkValue = myFile.ReadByte();
            }
            rowCount = enterCount + 1;
            return rList;
        }

執行的代碼:

 

            Stopwatch stopwatch = new Stopwatch();
            stopwatch.Start();
            int rowCount;
            FileHelper.ScanEnterFile(@"R:\201201_dataFile.txt", out rowCount, 35, outputProgress);
            useTime = stopwatch.ElapsedMilliseconds;

執行結果是:

124925  ms

(經過眾多網友的批評與指點,該方法並沒有把檔案讀取記憶體中,而是逐個位元組地讀取,速度比Delphi位元組讀進記憶體的方法要慢很多。這種方法只適合於老機器,記憶體不夠的情況下,當今記憶體已經很便宜了,所以,該方法目前已經過時了,下面經過網友的指點,使用了readline的方法,速度大概是6秒左右。)

 

        public static IList<long> ScanEnterFile(string fileName, ThreadProgress progress)
        {
            if (string.IsNullOrEmpty(fileName))
                return null;
            if (!System.IO.File.Exists(fileName))
                return null;
            IList<long> rList = new List<long>();
            rList.Add(0);
            StreamReader sr = File.OpenText(fileName);
            string rStr = sr.ReadLine();
            while (null != rStr)
            {
                rList.Add(rList[rList.Count-1] + rStr.Length + 2);
                rStr = sr.ReadLine();
                progress(rList.Count);
            }
            sr.Close();
            return rList;
        }

 

經過測試,該方法如果存在中文字元編碼的時候,其位置是錯誤的。日後找到解決方案後,再上來更新。

經過測試,C#的使用IList<T>比數組的要快。

總結:任何事物都有其存在的價值,至於看官門選什麼,就根據自己的需要,來選擇,這裡,本人不會有任何偏向於哪一方。反正,能成事,什麼都不重要了。

原創作品出自努力偷懶,轉載請說明文章出處:http://blog.csdn.net/kfarvid或 http://www.cnblogs.com/kfarvid/ 

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.