C#快速随机按行读取大型文本文件

原文:C#快速随机按行读取大型文本文件

下面是我实现的一个数据文件随机读取类,可以随机读取大型文本文件的某一行。在我机器上对一个130MB的文本文件,读取第200000的速度从传统做法的400ms提高到了3ms。
一般对文本文件进行读取时,一般采用ReadLine()进行逐行读取。在这种情况下,C#内的FileStream和BufferedStream类处理绰绰有余了。它不会将整个文件全部读入,而是有缓冲的读。但是,要想随机读取某一行,在行数据长度不统一的情况下,如果每次这样遍历到指定行,其效率显然是很低下的。
当然,代价也是有的,引入了第一次打开文件的打开时间,且占用了少部分内存(占用多少是可以设置的,当然占得越小速度也越慢,但最大值也比全部读入要小很多)。

(对网络代码进行部分改写)

using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;
using System.Threading;
using System.IO;

namespace DataBuffer
{
    public static class FileConfig
    {
        public static int STREAM_BUFFER_SIZE = 1024000;
        public static int MAP_DISTANCE = 10;
    }

public class DataFile
    {
        ///
        /// 数据文件名
        ///
        public string fileName = "";
        ///
        /// 初始化读取完标志
        ///
        public bool done = false;

///
        /// 当前流位置
        ///
        public long Position = 0;

///
        /// 文件头部信息
        ///
        private Hashtable head = new Hashtable();
        public Hashtable Head { get { return head; } set { head = value; } }

///
        /// 文件地图
        ///       
        private ArrayList map = new ArrayList();
        public ArrayList Map { get { return map; } set { map = value; } }

///
        /// 文件数据行行数
        ///       
        private long lines = 0;
        public long Lines { get { return lines; } set { lines = value; } }
    }

public class DataBuffer
    {
        private FileStream fs = null;
        private BufferedStream bs = null;
        private StreamReader sr = null;
        private StreamWriter sw = null;
        ///
        /// 文件信息数据结构
        ///
        public DataFile dataFile = new DataFile();

public DataBuffer(string name)
        {
            dataFile.fileName = name;
        }

///
        /// 打开文件
        ///
        public bool Open()
        {
            try
            {
                //初始化各流
                fs = new FileStream(dataFile.fileName, FileMode.Open, FileAccess.ReadWrite);
                bs = new BufferedStream(fs, FileConfig.STREAM_BUFFER_SIZE);
                sr = new StreamReader(fs);
                sw = new StreamWriter(fs);
                Thread initFile = new Thread(new ThreadStart(InitDataFile));
                initFile.Start();
                return true;
            }
            catch (Exception ee)
            {
                ErrorHandler.ErrorHandler eh = new ErrorHandler.ErrorHandler(ee, "文件打开");
                return false;
            }
        }

private void InitDataFile()
        {
            //另开一个读取流
            BufferedStream bs = new BufferedStream(fs);
            StreamReader sr = new StreamReader(bs);

//读入数据文件头信息。共14行
            string thisLine = NextLine(ref sr);
            dataFile.Head.Add("Subject", thisLine.Substring(11));

thisLine = NextLine(ref sr);
            dataFile.Head.Add("Date", thisLine.Substring(8));

thisLine = NextLine(ref sr);
            dataFile.Head.Add("Time", thisLine.Substring(8));

thisLine = NextLine(ref sr);
            dataFile.Head.Add("Channels", thisLine.Substring(12));

thisLine = NextLine(ref sr);
            dataFile.Head.Add("Rate", thisLine.Substring(8));

thisLine = NextLine(ref sr);
            dataFile.Head.Add("Type", thisLine.Substring(8));

thisLine = NextLine(ref sr);
            dataFile.Head.Add("Rows", thisLine.Substring(8));

thisLine = NextLine(ref sr);
            thisLine = NextLine(ref sr);
            dataFile.Head.Add("Electrode Labels", thisLine);
            thisLine = NextLine(ref sr);
            thisLine = NextLine(ref sr);
            thisLine = NextLine(ref sr);
            thisLine = NextLine(ref sr);
            thisLine = NextLine(ref sr);
            //降低自己的优先级
            Thread.CurrentThread.Priority = ThreadPriority.BelowNormal;

//数行数,建立地图
            long lines = 1;
            //在地图中加入首条数据的位置信息
            dataFile.Map.Add(dataFile.Position);
            //顺序建立文件地图
            while (!sr.EndOfStream)
            {
                thisLine = NextLine(ref sr);
                if ((++lines) % FileConfig.MAP_DISTANCE == 0)
                {
                    dataFile.Map.Add(dataFile.Position);
                }
            }
            dataFile.Lines = lines;
            dataFile.done = true;
        }

///
        /// 文件关闭
        ///
        public bool Close()
        {
            try
            {
                //顺序关闭各流
                sw.Close();
                sr.Close();
                bs.Close();
                fs.Close();
                return true;
            }
            catch (Exception ee)
            {
                ErrorHandler.ErrorHandler eh = new ErrorHandler.ErrorHandler(ee, "文件关闭");
                return false;
            }
        }

///
        /// 顺序读取下一行。效率低不建议大规模使用,只在打开文件的时候使用一次
        ///
        ///
        public string NextLine(ref StreamReader sr)
        {
            string next = sr.ReadLine();
            //+2是指Windows换行回车。Linux下要改为+1
            dataFile.Position += next.Length + 2;
            return next;
        }

//指定的目标行内容
        public string ReadLine(long line)
        {
            try
            {
                //如果载入完毕
                if (dataFile.done)
                {
                    //确定数据块索引号
                    int index = (int)line / FileConfig.MAP_DISTANCE;
                    //移动到指定位置
                    bs.Seek(long.Parse(dataFile.Map[index].ToString()), SeekOrigin.Begin);
                    //创建流读取器
                    sr = new StreamReader(bs);
                    //移动到指定行
                    for (int i = 1; i <= (line - index * FileConfig.MAP_DISTANCE); i++)
                    {
                        sr.ReadLine();
                    }
                    //返回指定行的值
                    return sr.ReadLine();
                }
                else
                {
                    return "";
                }
            }
            catch (Exception ee)
            {
                ErrorHandler.ErrorHandler eh = new ErrorHandler.ErrorHandler(ee, "文件读取");
                return "";
            }
        }
    }

}

时间: 2024-10-12 20:49:02

C#快速随机按行读取大型文本文件的相关文章

PHP快速按行读取CSV大文件的封装类分享(也适用于其它超大文本文件)

CSV大文件的读取已经在前面讲述过了(PHP按行读取.处理较大CSV文件的代码实例),但是如何快速完整的操作大文件仍然还存在一些问题. 1.如何快速获取CSV大文件的总行数? 办法一:直接获取文件内容,使用换行符进行拆分得出总行数,这种办法对小文件可行,处理大文件时不可行:办法二:使用fgets一行一行遍历,得出总行数,这种办法比办法一好一些,但大文件仍有超时的可能:办法三:借助SplFileObject类,直接将指针定位到文件末尾,通过SplFileObject::key方法获取总行数,这种办

Java如何实现按指定行读取文件

最近在开发实战中,遇到了一个这样的技术情景: 把log4j生成的日志文件定时刷进MySQL数据库,比如三个小时刷一次,那么每次刷数据的时候,如何控制文件读取是从上一次文件读取结束的地方开始继续读取的?并且本次要读取到文件结尾处.在网上各种搜索提问后,找到了一个叫RandomAccessFile Java类解决了问题. 先上代码: static int size=1;//主要是为了控制循环的次数,因为是定时刷,每次刷的文件行数可能不一样 static long chars=0;//chars指的是

c#分页读取GB文本文件

原文:c#分页读取GB文本文件 应用场景: a.我在做BI开发测试的时候,有可能面对source文件数GB的情况,如果使用一般的文本编辑器,则会卡死,或要等很久才能显示出来. b.有时候,我们使用ascii(01)或ascii(02)作为行或列的分隔符,这样的临时文件用于导数据到DB,如果文件导入过程中有错误,需要查看文件 的时候,普通的编辑器不支持换行,则会很恐怖. 为解决这两个需求,我使用c#完成了一个简单的winform的应用程序. 功能列表: 1.根据配置的行数,写测试文件,指定行终止符

关于一些对map和整行读取文件操作

public static void main(String[] args) { Map<String, String> map = new HashMap<String, String>();  map.put("1", "value1");  map.put("2", "value2");  map.put("3", "value3");    //第一种:普

sql脚本读取txt文本文件插入新表

今天老大让我录入一大批数据,我的第一个想法就是用inser来一条条插入,或者用C#代码读取Excel然后再插入到数据库,经过老大的介绍.我才知道,还有用sql脚本导入数据的方法.呵呵,真的是长知识了.其实代码很简单 BULK INSERT cartemp FROM 'd:\1.txt' WITH( FIELDTERMINATOR = '\t', ROWTERMINATOR = '\n' ) 可是执行后一直报这样的错误.让我找不到原因,百度了好多解释,却解决不了我的问题 消息 4832,级别 16

c#分页读取GB文本文件实例

本文实例讲述了c#分页读取GB文本文件的方法.分享给大家供大家参考.具体如下: 一.应用场景: ① .我在做BI开发测试的时候,有可能面对source文件数GB的情况,如果使用一般的文本编辑器,则会卡死,或要等很久才能显示出来. ② .有时候,我们使用ascii(01)或ascii(02)作为行或列的分隔符,这样的临时文件用于导数据到DB,如果文件导入过程中有错误,需要查看文件 的时候,普通的编辑器不支持换行,则会很恐怖. 为解决这两个需求,我使用c#完成了一个简单的winform的应用程序.

python 按每行读取文件怎么去掉换行符

python按每行读取文件后,会在每行末尾带上换行符,这样非常不方便后续业务处理逻辑,需要去掉每行的换行符,怎么去掉呢?看下面的案例: >>> a = "hello world\n" >>> print a #可以看到hello world下面空了一格 hello world >>> a.split() #通过split方法将字符转换成列表 ['hello', 'world'] #从列表中取第一个字符 >>> a.

Java利用内存映射文件实现按行读取文件

我们知道内存映射文件读取是各种读取方式中速度最快的,但是内存映射文件读取的API里没有提供按行读取的方法,需要自己实现.下面就是我利用内存映射文件实现按行读取文件的方法,如有错误之处请指出,或者有更好更快的实现方式麻烦也提供一下代码. 代码如下: public class testMemoryMappedFile { public static void main(String[] agrs) throws IOException{ RandomAccessFile memoryMappedFi

实现按行读取文件,把内容按照第三种内存模型打包数据传出,把行数通过函数参数传出。

/* 2 编写一个业务函数,实现按行读取文件.把内容按照第三种内存模型打包数据传出,把行数通过函数参数传出. 函数原型有两个,任意选择其一 要求1:请自己任意选择一个接口(函数),并实现功能:70分 要求2:编写测试用例.30分 要求3:自己编写内存释放函数 */ /********************************************************************** * 版权所有 (C)2015, Wu Yingqiang. * * 文件名称:ReadFi