快速扫描文本文件,统计行数,并返回每一行的索引位置(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])=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/
http://www.cnblogs.com/kfarvid/archive/2012/01/12/2320692.html
快速扫描文本文件,统计行数,并返回每一行的索引位置(Delphi、C#)的更多相关文章
- C++->10.3.2-3,使用文件流类录入数据,并统计行数
题目:建立一个文本文件,从键盘录入一篇短文存放在该文件中短文由若干行构成,每行不超过80个字符,并统计行数. /* #include<iostream.h>#include<stdl ...
- Hbase Java API包括协处理器统计行数
package com.zy; import java.io.IOException; import org.apache.commons.lang.time.StopWatch; import or ...
- 《c程序设计语言》读书笔记--统计 行数、单词数、字符数
#include <stdio.h> int main() { int lin = 0,wor = 0,cha = 0; int flag = 0; int c; while((c = g ...
- shell 统计行数
语法:wc [选项] 文件… 说明:该命令统计给定文件中的字节数.字数.行数.如果没有给出文件名,则从标准输入读取.wc同时也给出所有指定文件的总统计数.字是由空格字符区分开的最大字符串. 该命令各选 ...
- linux、WINDOWS命令行下查找和统计行数
linux : 例子: netstat -an | grep TIME_WAIT | wc -l | 管道符 grep 查找命令 wc 统计命令 windows: 例子: netstat -an | ...
- wc 统计行数 字数
Linux统计文件行数 2011-07-17 17:32 by 依水间, 168255 阅读, 4 评论, 收藏, 编辑 语法:wc [选项] 文件… 说明:该命令统计给定文件中的字节数.字数.行数. ...
- SQL Server遍历所有表统计行数
DECLARE CountTableRecords CURSOR READ_ONLY FOR SELECT sst.name, Schema_name(sst.schema_id) FROM sys. ...
- Python,针对指定文件类型,过滤空行和注释,统计行数
参考网络上代码编辑而成,无技术含量,可自行定制: 目前亲测有效,若有待完善之处,还望指出! 强调:将此统计py脚本放置项目的根目录下执行即可. 1.遍历文件,递归遍历文件夹中的所有 def getFi ...
- oracle查询表统计行数与注释
SELECT TABLE_NAME,NUM_ROWS,(select COMMENTS from user_tab_comments WHERE TABLE_NAME=C.TABLE_NAME) FR ...
随机推荐
- SSH无密码登陆问题解决
转载 http://my.oschina.net/hunzi/blog/10687 安装好Cygwin后,SSH需要设置为无密码登陆, 首先查看是ssh还是ssh2:ls -l `which ssh` ...
- 编码神器之sublime(插件安装)
一款优秀的编辑器是程序员的左膀右臂,相信每一个程序员手边都有自己熟悉的编辑器. 从一开始使用sublime的时候就开始喜欢上了这款编辑器,被他强大的功能深深的吸引了. sublime的强大来源于他的扩 ...
- Windows Forms(二)
导读 1.用VS创建一个Windows Forms程序 2.分析上面的程序 3.Mediator pattern(中介者模式) 4.卡UI怎么办——BackgroundWorker组件 用VS创建一个 ...
- MSBuild could not create or connect to a task host with runtime "CLR2" and architecture "x86".
vs2010 and vs2012 are installed on target machine. Build c# project using vs2010, following error oc ...
- (转)MySQL Workbench的使用教程 (初级入门版)
转自:http://www.cnblogs.com/yqskj/archive/2013/03/01/2938027.html MySQL Workbench 是 MySQL AB 最近释放的可视数据 ...
- DB2数据库中提高INSERT性能详解
分类: Linux INSERT 处理过程概述 首先让我们快速地看看插入一行时的处理步骤.这些步骤中的每一步都有优化的潜力,对此我们在后面会一一讨论. 在客户机准备 语句.对于动态 SQL,在 ...
- hdu 5056 Boring count
贪心算法.需要计算分别以每个字母结尾的且每个字母出现的次数不超过k的字符串,我们设定一个初始位置s,然后用游标i从头到尾遍历字符串,使用map记录期间各个字母出现的次数,如果以s开头i结尾的字符串满足 ...
- Entity Framework多对多关联映射的实现
Entity Framework是微软官方提供的一个ORM解决方案,它有纯正的血统,比NHibernate更容易使用并且与现有其它官方框架配合更加密切. 时代不断的在发展变化,记得10年前还是ADO( ...
- memcached全面剖析--4
memcached的分布式算法 memcached的分布式 正如第1次中介绍的那样, memcached虽然称为“分布式”缓存服务器,但服务器端并没有“分布式”功能. 服务器端仅包括 第2次. 第 ...
- R语言语法笔记
## 1. 数据输入 ## a$b # 数据框中的变量 a = 15 # 赋值 a <- 15 # 赋值 a = c(1,2,3,4,5) # 数组(向量) b = a[1] # 数组下标,从1 ...