C#读取大容量Txt文件的问题

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C#读取大容量Txt文件的问题相关的知识,希望对你有一定的参考价值。

我用分页方式读取一个10M的Txt文件(共约140万条记录),结果出来只有142条记录,代码如下:
private void button1_Click(object sender, EventArgs e)

int i = 0;
//线程每次读取文件100K
const long ChunkSize = 102400;
//清理非托管不受GC控制的资源,using结束后会隐式的调用Disposable方法
using (OpenFileDialog fbd = new OpenFileDialog())

fbd.Filter = "文本文件|*.txt";
if (fbd.ShowDialog(this) == DialogResult.OK)

byte[] bytcontent = new byte[ChunkSize];
FileStream fs = new FileStream(fbd.FileName, FileMode.Open);
//获取文件总大小
long dataLengthToRead = fs.Length;

while (dataLengthToRead > 0)

//读取的大小
int lengthRead = fs.Read(bytcontent, 0, Convert.ToInt32(ChunkSize));
Thread t = new Thread(new ParameterizedThreadStart(Readfile));
t.Start(System.Text.Encoding.Default.GetString(bytcontent));
dataLengthToRead -= lengthRead;
i++;




this.label4.Text = "共有:"+i.ToString()+"条记录!";

超出最大字符数 ,分两次发
public delegate void Callback(string str);
private void Readfile(object content)

if (richTextBox1.InvokeRequired)

Callback call = new Callback(Readfile);
this.BeginInvoke(call, new object[] content );

else

this.richTextBox1.AppendText(content.ToString());
this.richTextBox1.AppendText("\r\n");

你这代码有几个问题:

首先,你这记录论“条”,实际的条数只是总字节数除ChunkSize的值,个人建议你这要是计数的是行数就更好了,这可以用StreamReader.ReadLine实现,如果你的文件10M,文件大小就是10*1024*1024,你的ChunkSize是102400,记录数自然是10*1024*1024/102400=102.4,你这142条记录应该有10M多一些,没什么不对的

其次,多线程输出到RichTextBox显然画蛇添足,反而会导致RichTextBox中的内容顺序跟文件可能不一致,因为开启多线程之后顺序是不一定的

第三,多线程开销是很大的,你这短时间内while循环那么多次就开启了大量的多线程,每个线程就给RichTextBox赋值这太浪费了

至于性能问题,跟其他几位说的一样,瓶颈在磁盘读写,你这多线程处理RichTextBox没什么意义

            const long ChunkSize = 102400;
            byte[] bytcontent = new byte[ChunkSize];
            FileStream fs = new FileStream(@"C:\\unintall.log", FileMode.Open);
            int i = 0;
            while (fs.Read(bytcontent, 0, bytcontent.Length) > 0)
            
                i++;
                Console.Write(System.Text.Encoding.Default.GetString(bytcontent));
            
            Console.WriteLine("共有:" + i + "条记录!");

下面是ReadLine的

            using (StreamReader sr = new StreamReader(@"C:\\unintall.log", System.Text.Encoding.Default))
            
                while (sr.Peek() >= 0)
                
                    Console.WriteLine(sr.ReadLine());
                
            

参考

https://msdn.microsoft.com/zh-cn/library/system.io.streamreader.readline.aspx

参考技术A 晕了。你这句
this.label4.Text = "共有:"+i.ToString()+"条记录!";

这个i只是你循环次数,怎么是记录数呢。

还有你多线程,如果没出问题也只能因为你的磁盘速慢,导致读取速度跟不上线程速度,否则显示的数据一定是乱的。追问

是的,this.label4.Text = "共有:"+i.ToString()+"条记录!";这句应该写成this.label4.Text = "共有:"+this.richTextBox2.Lines.Length.ToString()+"条记录!"。

至于你说的线程读取数据是乱的,还有没有其它的方法?StreamReader可以吗?

追答

按你的功能,不需要多线程,
直接 this.richTextBox1.AppendText,在后面再加一句Application.DoEvents();就不会卡界面

本回答被提问者采纳
参考技术B FileStream常用的属性和方法:
  属性:
  CanRead 判断当前流是否支持读取,返回bool值,True表示可以读取
  CanWrite 判断当前流是否支持写入,返回bool值,True表示可以写入
  方法:
  Read() 从流中读取数据,返回字节数组
  Write() 将字节块(字节数组)写入该流
  Seek() 设置文件读取或写入的起始位置
  Flush() 清除该流缓冲区,使得所有缓冲的数据都被写入到文件中
  Close() 关闭当前流并释放与之相关联的所有系统资源
  文件的访问方式:(FileAccess)
  包括三个枚举:
  FileAccess.Read(对文件读访问)
  FileAccess.Write(对文件进行写操作)
  FileAccess.ReadWrite(对文件读或写操作)
  文件打开模式:(FileMode)包括6个枚举
  FileMode.Append 打开现有文件准备向文件追加数据,只能同FileAccess.Write一起使用
  FileMode.Create 指示操作系统应创建新文件,如果文件已经存在,它将被覆盖
  FileMode.CreateNew 指示操作系统应创建新文件,如果文件已经存在,将引发异常
  FileMode.Open 指示操作系统应打开现有文件,打开的能力取决于FileAccess所指定的值
  FileMode.OpenOrCreate 指示操作系统应打开文件,如果文件不存在则创建新文件
  FileMode.Truncate 指示操作系统应打开现有文件,并且清空文件内容
  文件共享方式:(FileShare)
  FileShare方式是为了避免几个程序同时访问同一个文件会造成异常的情况。
  文件共享方式包括四个:
  FileShare.None 谢绝共享当前文件
  FileShare.Read 充许别的程序读取当前文件
  FileShare.Write 充许别的程序写当前文件
  FileShare.ReadWrite 充许别的程序读写当前文件
  使用FileStream类创建文件流对象:
  FileStream(String 文件路径,FileMode 文件打开模式)
  FileStream(String 文件路径,FileMode 文件打开模式,FileAccess 文件访问方式)
  FileStream(String 文件路径,FileMode 文件打开模式,FileAccess 文件访问方式,FileShare 文件共享方式)
  例:
  //在C盘创建a.txt文件,使用fs流对象对文件进行操作,fs的工作模式是新建(FileMode.Create)
  FileStream fs=new FileStream(@"c:a.txt",FileMode.Create);
  //在C盘创建a.txt文件,使用fs流对象对文件进行操作,fs工作模式是新建(FileMode.Create)文件的访问模式是写入(Fileaccess.Write)
  FileStream fs=new FileStream(@"c:a.txt",FileMode.Create,FileAccess.Write);
  //在C盘创建a.txt文件,使用fs流对象对文件进行操作,fs工作模式是新建(FileMode.Create)文件的访问模式是写入(FileAccess.Write)文件的共享模式是谢绝共享(FileShare.None)
  FileStream fs=new FileStream(@"c:a.txt",FileMode.Create,FileAccess.Write,FileShare.None);
  使用File类来创建对象:(常用)
  自定义打开文件的方式:File.Open(String,FileMode);
  打开文件进行读取: File.OpenRead(String);
  打开文件进行写入: File.OpenWrite(String);
  示例如下:
  //在C盘新建123.txt文件,使用流对象fs对文件进行操作,fs可以行文件内容追加操作FileMode.Append
  FileStream fs=File.Open(@"c:123.txt",FileMode.Append);
  //在C盘新建123.txt文件,使用流对象fs对文件进行操作,fs可以进行读文件File.OpenRead()
  FileStream fs=File.OpenRead(@"c:123.txt");
  //在C盘新建123.txt文件,使用流对象fs对文件进行操作,fs可以进行写操作File.OpenWrite()
  FileStream fs=File.OpenWrite(@"c:123.txt");
  使用File例:
  对文件进行读操作:
  //新建fs流对象对象产生的路径是textbox1.text的值,文件的模式是FileMode.OpenOrCreate(可读可写)
  using (FileStream fs = File.Open(textBox1.Text, FileMode.OpenOrCreate))
  
  //新建字节型数组,数组的长度是fs文件对象的长度(后面用于存放文件)
  byte[] bt=new byte[fs.Length];
  //通过fs对象的Read方法bt得到了fs对象流中的内容
  fs.Read(bt,0,bt.Length);
  //关闭fs流对象
  fs.Close();
  //将bt字节型数组中的数据由Encoding.Default.GetString(bt)方法取出,交给textbox2.text
  textBox2.Text = System.Text.Encoding.Default.GetString(bt);
  
  对文件进行写入操作:
  //新建fs流对象,对象操作的文件路径在textbox1.text中,fs的操作模式是FileMode.Create
  using (FileStream fs = File.Open(textBox1.Text, FileMode.Create))
  
  //新建字节型数组bt对象,bt对象得到了textbox2.text的Encoding的值
  byte[] bt = System.Text.Encoding.Default.GetBytes(textBox2.Text);
  //将bt字节型数组对象的值写入到fs流对象中(文件)
  fs.Write(bt,0,bt.Length);
  //关闭流对象
  fs.Close();
  
  注:
  对文件的读写操多不管代码有多少,无非就是下面的三步:
  1.创建文件读写流对象
  2.对文件进行读写
  3.关闭文件流
参考技术C 你很牛啊,直接就处理了!!
你这个数据读出来不会乱七八糟的么?追问

这是用多线程处理,不卡啊

追答

我不是说卡不卡,是你读出来的数据不错乱?

追问

是的,this.label4.Text = "共有:"+i.ToString()+"条记录!";这句应该写成this.label4.Text = "共有:"+this.richTextBox2.Lines.Length.ToString()+"条记录!"。

至于你说的线程读取数据是乱的,还有没有其它的方法?StreamReader可以吗?

追答

其实你只需要在线程中读取数据然后更新UI就可以了,不用读数据在一个线程,更新UI又在另外的线程,同时你的读和更新表面上是分包同步,实际上会出现数据显示先后不同或者资源争抢造成线程异常,至于用什么方式读写都无所谓

C#处理文本文件TXT实例详解

本文实例讲述了C#处理文本文件TXT的方法。分享给大家供大家参考。具体分析如下:


1. 如何读取文本文件内容:

这里介绍的程序中,是把读取的文本文件,用一个richTextBox组件显示出来。要读取文本文件,必须使用到”StreamReader”类,这个类是由名字空间”System.IO”中定义的。通过”StreamReader”类的”ReadLine()”方法,就可以读取打开数据流当前行 的数据了。下面代码实现的功能就是读取”C:\file.txt”并在richTextBox1组件中显示出来:

FileStreamfs=newFileStream("C:\\file.txt",FileMode.Open,FileAccess.Read);
StreamReaderm_streamReader=newStreamReader(fs);
//使用StreamReader类来读取文件
m_streamReader.BaseStream.Seek(0,SeekOrigin.Begin);
//从数据流中读取每一行,直到文件的最后一行,并在richTextBox1中显示出内容
this.richTextBox1.Text="";
stringstrLine=m_streamReader.ReadLine();
while(strLine!=null)
{
this.richTextBox1.Text+=strLine+"\n";
strLine=m_streamReader.ReadLine();
}
//关闭此StreamReader对象
m_streamReader.Close();


2. 如何改变文本文件中数据内容:

下面的程序中,改变文本文件数据内容的功能是通过改变richTextBox1中的内容来实现的,当richTextBox1这的内容改变后,按动”另存为”,就把richTextBox1中内容存储到指定的文本文件中了。要想改变文本文件内容,要使用到”StreamWriter”类,这个类 和”StreamReader”一样,都是由”System.IO”名字空间来定义的。通过”StreamWriter”类的”Write()”方 法,就可以轻松实现文本文件内容的更改了。下面代码的功能是:如果”C”盘存在”file.txt”,则把richTextBox1中的内容写入 到”file.txt”中,如果不存在,则创建此文件,然后在写入文本数据。

//创建一个文件流,用以写入或者创建一个StreamWriter
FileStreamfs=newFileStream("C\\file.txt",FileMode.OpenOrCreate,FileAccess.Write);
StreamWriterm_streamWriter=newStreamWriter(fs);
m_streamWriter.Flush();
//使用StreamWriter来往文件中写入内容
m_streamWriter.BaseStream.Seek(0,SeekOrigin.Begin);
//把richTextBox1中的内容写入文件
m_streamWriter.Write(richTextBox1.Text);
//关闭此文件
m_streamWriter.Flush();
m_streamWriter.Close();

从上面这二个代码可以,写入数据比起读取数据要显得容易些。


3. 如何实现打印预览:

打印预览是通过打印预览对话框来实现的,实现对读取得文本文件的打印预览,最为重要的就是要通知打印预览对话框所要预览的文件的内容。下面代码就是把richTextBox1中显示的内容,通过打印预览对话框显示出来:

stringstrText=richTextBox1.Text;
StringReadermyReader=newStringReader(strText);
PrintPreviewDialogprintPreviewDialog1=newPrintPreviewDialog();
printPreviewDialog1.Document=ThePrintDocument;
printPreviewDialog1.FormBorderStyle=FormBorderStyle.Fixed3D;
printPreviewDialog1.ShowDialog();


4. 如何打印文件:

在名字空间”System.Drawing.Printing”中定义了一个类”PrintDocument”,通过调用此类的”Print”方法就可 以触发在此名字空间中封装的另外一个事件”PrintPage”。在此事件中设定要打印的文档内容,从而实现队文本文件的打印操作。下面代码是调 用”PrintDocument”的”Print”方法,和调用事件”PrintPage”来打印richTextBox1中的内容:

ThePrintDocument.Print();//其中ThePrintDocument是"PrintDocument"类的一个对象

下列代码是设定打印内容即打印richTextBox1中的内容:

floatlinesPerPage=0;
floatyPosition=0;
intcount=0;
floatleftMargin=ev.MarginBounds.Left;
floattopMargin=ev.MarginBounds.Top;
stringline=null;
FontprintFont=richTextBox1.Font;
SolidBrushmyBrush=newSolidBrush(Color.Black);
//计算每一页打印多少行
linesPerPage=ev.MarginBounds.Height/printFont.GetHeight(ev.Graphics);
//重复使用StringReader对象,打印出richTextBox1中的所有内容
while(count<linesPerPage&&((line=myReader.ReadLine())!=null))
{
//计算出要打印的下一行所基于页面的位置
yPosition=topMargin+(count*printFont.GetHeight(ev.Graphics));
//打印出richTextBox1中的下一行内容
ev.Graphics.DrawString(line,printFont,myBrush,leftMargin,yPosition,newStringFormat());
count++;
}
//判断如果还要下一页,则继续打印
if(line!=null)
ev.HasMorePages=true;
else
ev.HasMorePages=false;
myBrush.Dispose();


注释:

由于在上述的代码中省掉了这些类所对于地名字空间,所以要想成功的编译和运行上述代码,就要在程序头部要导入所使用的名字空间。

希望本文所述对大家的C#程序设计有所帮助。

除声明外,跑步客文章均为原创,转载请以链接形式标明本文地址
  C#处理文本文件TXT实例详解

本文地址:  http://www.paobuke.com/develop/c-develop/pbk23148.html






相关内容





















以上是关于C#读取大容量Txt文件的问题的主要内容,如果未能解决你的问题,请参考以下文章

C# 读取TXT文件内容到listview

C#读取txt文件

c#中怎么读取txt文件的最后几行

C# 读取txt配置文件,并且可以更新配置文件

C# 读取txt文件生成Word文档

WPF C#怎么批量读取和创建文件(类似txt文件)