zoukankan      html  css  js  c++  java
  • 快速扫描文本文件,统计行数,并返回每一行的索引位置(Delphi、C#)

    由项目需要,需要扫描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])=13then
          addStep:=2;
        if (ord(pc[curIndex])=10then
          addStep:=1;
        //处理有回车的
        if (addStep<>0then
        begin
          Application.ProcessMessages;
          //增加一行记录
          inc(enterCount);
          //判断是否需要增大数组
          if (enterCount mod perArray=0then
          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/ 
  • 相关阅读:
    Java的静态块与实例块(转)
    Programming Ability Test学习 1031. Hello World for U (20)
    Programming Ability Test学习 1011. World Cup Betting (20)
    Programming Ability Test学习 1027. Colors in Mars (20)
    Programming Ability Test学习 1064. Complete Binary Search Tree (30)
    Programming Ability Test学习 1008. Elevator (20)
    【maven详解-生命周期】Maven的生命周期和插件
    【maven详解-插件】maven插件学习之源码插件Source Xref
    $(document).ready(){}、$(fucntion(){})、(function(){})(jQuery)onload()的区别
    你还没真的努力过,就轻易输给了懒惰
  • 原文地址:https://www.cnblogs.com/kfarvid/p/2320692.html
Copyright © 2011-2022 走看看