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();就不会卡界面
属性:
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文件的问题的主要内容,如果未能解决你的问题,请参考以下文章