C#逐行读取txt文件(超大文件支持)

最近笔者在写一个小程序的时候,遇到一个问题,相信这个问题很多朋友碰到了,即在使用系统提供的方法System.IO.StreamReader.ReadLine()时,遇到“OutOfMemoryException ”问题。 因需求目标就是逐行读取txt文件,然后进行数据解析,第一次碰到该问题还真是一脸懵逼。

经过实际测试,在读取几百兆字节以内的txt文件时,System.IO.StreamReader.ReadLine()方法为首选,但是当txt文件超过1GB后,大概率会出“OutOfMemoryException ”问题。此外该方法在读取的时候占用内存极高,笔者在使用该方法读取一个1.3GB的txt文件时,占用内存最高达2.7GB,最后报告“OutOfMemoryException ”问题。

关于该问题,微软的帮助文档是这样解释的:

如果当前方法引发,则 OutOfMemoryException 读取器在基础字符串中的位置将由该方法可以读取的字符数提前,但已读入内部缓冲区的字符将被 ReadLine 丢弃。 由于不能更改读取器在字符串中的位置,因此,已读取的字符不可恢复,只能通过重新初始化来访问 StringReader 。 若要避免这种情况,请使用 Read 方法并在预分配的缓冲区中存储读取字符。

写的这是个什么玩意?让初学编程的笔者属实难以理解! 经过琢磨,笔者使用了StreamReader.Read()方法,重写了一个类,实现了逐行读取txt文件的功能,具体实现如下:

先定义一个类:
//定义类开始

class ReadTxtFileLine
    {    //本类用于使用StreamReader.Read()方法,实现逐行读取文本文件,
        int _IsReadEnd = 0;  //文件读取的状态,当为false时,代表未读完最后一行,true为读完了最后一行
        System.IO.StreamReader sr1;
        int _LoopRowNumNow = 0;
        //定义了一个是否读到最后的属性,数据类型为整数
        public int IsReadEnd { get => _IsReadEnd; }
        //构造函数
        public ReadTxtFileLine(string TxtFilePath, Encoding FileEncoding)
        {
            sr1 = new System.IO.StreamReader(TxtFilePath, FileEncoding);
            _IsReadEnd = 1;
        }
        //成员方法,执行一次,返回1行的结果,当全部读完,依然执行该方法,将返回空字符串""
        public string GetLineStr()
        {
            string strLine = "";
            int charCode = 0;
            while (sr1.Peek() > 0)
            {
                charCode = sr1.Read();
                if (charCode == 10)  //发现换行符char10就返回拼接字符串
                {
                    _LoopRowNumNow++;
                    return strLine;
                }
                else
                {
                    if (charCode != 13)
                    {    //将一行的数据重新拼接起来
                        strLine += ((char)charCode).ToString();
                    }
                }
            }
            _IsReadEnd = -1;
            sr1.Close();
            sr1.Dispose();
            return strLine;
        }
    }

//定义类结束

假设在控制台的main方法中使用:
要读取的文本文件为一个UTF8编码的txt文件,内容如下:
使用Windows换行标识符

假设需要在控制台程序的main方法中逐行读取并打印,代码如下:

  string path = @"D:\测试样例.txt";
            Encoding encoding = UTF8Encoding.UTF8;
            ReadTxtFileLine ReadTxtFileTest1 = new ReadTxtFileLine(path, encoding);

            while (ReadTxtFileTest1.IsReadEnd>0)
            {
                string str = ReadTxtFileTest1.GetLineStr();  //这里将读出来的1行赋值给str
                Console.WriteLine("本行的数据为:{0}",str);
            }

            Console.ReadLine();

执行结果如下图所示:
执行结果
使用注意事项:
1、该类有个属性IsReadEnd ,取值为0,代表未开始读和未生效,取值为-1,代表整个文件已经读取结束
2、当属性IsReadEnd 为-1时,代表文件已经读取结束。此时执行成员方法GetLineStr(),将会返回一个空字符串“”。
3、读取过程中内存占用率非常低,绝对不会出现StringReader.ReadLine方法在遇到大文件时抛出的错误。
4、只能从文件的前读到后,不能切换到任意行读取。
5、在文件读取完毕后,反复执行成员方法GetLineStr(),将会反复返回空字符串“”,可以通过属性字段IsReadEnd 的取值判断是否需要当前的返回值。

  • 4
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值