原文: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 "";
            }
        }
    }

}

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

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

    CSV大文件的读取已经在前面讲述过了(PHP按行读取.处理较大CSV文件的代码实例),但是如何快速完整的操作大文件仍然还存在一些问题. 1.如何快速获取CSV大文件的总行数? 办法一:直接获取文件内容 ...

  2. Java中文本文件的读取(按行读取)

    在之前的学习过程中,经常会遇到将文本文件中的数据读取到数组或其他数据结构中.每次遇到,总是在网上搜索代码解决,解决之后并没有总结复习,因此在下一次遇到同样的问题时,又重复之前的过程.这样周而复始,并没 ...

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

    public static void main(String[] args) { Map<String, String> map = new HashMap<String, Stri ...

  4. J2SE 8的输入输出--读取/写入文本文件和读取/写入二进制数据

    读取/写入文本文件 // 1. 文本输入 // (1) 短小文本直接转入字符串 String string = new String(Files.readAllBytes(Paths.get(&quo ...

  5. C++按行读取和写入文件

    按行读取: 假设有一个文本文件,如下所示: 1 2 32 3 43 4 55 6 77 8 9 文件名为split.txt 目的:按照行读取数据,并一个个的显示出来. 代码如下: #include & ...

  6. c/c++ 按照行读取文件

    本文代码都在Windows/VC++6.0下测试过, 在linux/g++下也没有问题. 但是请一定注意linux和Windows文件格式的区别,比如: 1. 当linux上的代码读取Windows文 ...

  7. 性能测试--Jmeter随机生成/随机选取/csv读取关键字

    Jmeter随机生成/随机选取/csv读取关键字 一.随机生成关键字 随机生成关键字,需要组件:随机变量配置元件(Random Variable)  该组件的作用是生成字符+随机数字格式的字符串,并保 ...

  8. Apache Commons CLI官方文档翻译 —— 快速构建命令行启动模式

    昨天通过几个小程序以及Hangout源码学习了CLI的基本使用,今天就来尝试翻译一下CLI的官方使用手册. 下面将会通过几个部分简单的介绍CLI在应用中的使用场景. 昨天已经联系过几个基本的命令行参数 ...

  9. asp.net 读取一个文本文件,并输出到网页显示 通过 一般处理程序实现

    asp.net 读取一个文本文件,并输出到网页显示 通过 一般处理程序实现 用这个可以做模板首页进行输出,也可以自已自定义进行扩展 //得到读取到的文本到string中 string resultTe ...

随机推荐

  1. [SignalR]Self-Host

    原文:[SignalR]Self-Host SignalR 的Self-Host,可以将客户端脚本需要调用的服务端后台代码寄宿在诸如控制台应用程序中,作为寄宿端需要.NET 4.5以及jquery.s ...

  2. BZOJ 1212 HNOI2004 L语言 AC自己主动机(Trie树)+动态规划

    标题效果:给定词的列表,并m串 每个字符串q个最长前缀,这个前缀可满足拆分成一些字符串 这些字符串中存在的词汇太 再也不怕错误的数据范围--有一个很明显Trie树能解决的问题竟然被我写的AC自己主动机 ...

  3. java处理Excel文件---excel文件的创建,删除,写入,读取

    这篇文章的代码是我封装的excel处理类,包含推断excel是否存在,表格索引是否存在,创建excel文件,删除excel文件,往excel中写入信息,从excel中读取数据. 尤其在写入与读取两个方 ...

  4. 【Hibernate步步为营】--复合主键映射具体解释

    上篇文章讨论了继承映射,它是对象模型中最主要的特性,对于继承映射它的主要区分是字段类型的不同,所以在生成表结构时须要有新列来标识数据的类型,能够使用<subclass>标签并在标签中加入d ...

  5. jvm对大对象分配内存的特殊处理(转)

    前段日子在和leader交流技术的时候,偶然听到jvm在分配内存空间给大对象时,如果young区空间不足会直接在old区切一块过去.对于这个结论很好奇,也比较怀疑,所以就上网搜了下,发现还真有这么回事 ...

  6. IE8升级新版Flash Player ActiveX14导致的discuz图片附件无法上传 解决方法

    架不住sb adobe的频繁升级提示,手欠升级到了了flash player 14,结果IE8下全部discuz论坛中都无法看到上传图片的button了 没办法,遇到问题就解决吧 刚好在解决IE11遇 ...

  7. Entity Framework加载相关实体——延迟加载Lazy Loading、贪婪加载Eager Loading、显示加载Explicit Loading

    Entity Framework提供了三种加载相关实体的方法:Lazy Loading,Eager Loading和Explicit Loading.首先我们先来看一下MSDN对三种加载实体方法的定义 ...

  8. iOS开发之protocol和delegate

     protocol--协议 协议是用来定义对象的属性,行为和用于回调的.     协议中有两个keyword@private和@optional,@private表示使用这个协议必需要写的方法,@op ...

  9. 【百度地图API】如何批量转换为百度经纬度

    原文:[百度地图API]如何批量转换为百度经纬度 摘要: 百度地图API的官网上提供了常用坐标转换的示例.但是,一次只能转换一个,真的非常麻烦!!这里结合了官方的示例,自制一个批量转换工具,供大家参考 ...

  10. 在面对变化,撇开NO

    参观后转到供应商,看到自己的生产线流水线半自己的钣金生产线举措.这就是我一直想厂提高生产现场的想法,因为通常当我看到工作人员努力工作和繁忙的生产,只见废现场,线解决方式时,有点莫名的兴奋. 幸亏是一家 ...