大文本文件的读取与写入
问题:现有一大文本文件预计300M,无法直接读入内存处理,现在的想法是每次从这个文件中读取n行进行处理,处理后其中的部分行需要再存入一个新的文本,估计这个新的文本也有几十M,那我怎么才能不把整个文件读入内存还能够每次读取n行呢?怎样才能都将n行的处理结果追加到新文本中呢?
最后祝大家新年快乐!
我晕,什么文本这么大啊?
每次读取N行貌似也不好处理,这么大个文本不能拆开么?
现在的问题是能够处理就可以,不追求速度!我每次读N行也就是为了拆开处理阿
不大了,我刚才看到人家一下读1.5g进去,也不知道怎么读的
300M...
我经常处理几个G的文本文件...
StreamReader读就好了
to shrinerain(圣影雨),俄的神阿,能贴点code吗?是一次子就读进去然后进行处理吗?
http://www.Codefund.cn/develop/Article/25/25337.shtm
小弟学C#不久,写一个,仅供参考..
static void Main(string[] args)
{
StreamReader sr = new StreamReader(new FileStream(@"C:\test\input.txt", FileMode.Open));
StreamWriter sw = new StreamWriter(new FileStream(@"C:\test\output.txt", FileMode.Append));
while (sr.Peek() > 0)
{
//计数器
int count = 0;
//用一个列表存储读出的N行,相当于一个缓冲
ArrayList list = new ArrayList();
while (sr.Peek() > 0 && count < 10)
{
//每次读10行
list.Add(sr.ReadLine());
count++;
}
//对读出的10行(有可能小于10),进行处理
foreach (string str in list )
{
//比如截取每个字符串的第一个字符,然后写入文件中
sw.Write(str.Substring(0, 1));
}
sw.Flush();
}
sr.Close();
sw.Close();
}
在Codeproject上搜索CSVReader,是你想要的东西...
TO liujia_0421(SnowLover):按照这个意思我完全可以一次把300M数据读进内存咯,那也不同再每次读N行进行处理,直接处理岂不是更好?
TO shrinerain(圣影雨):看了一下没完全看懂
<PRE lang=cs>using System.IO;
using LumenWorks.Framework.IO.Csv;
void ReadCsv()
{
// open the file "data.csv" which is a CSV file with headers
using (CsvReader csv =
new CsvReader(new StreamReader("data.csv"), true))
{
int fieldCount = csv.FieldCount;
string[] headers = csv.GetFieldHeaders();
while (csv.ReadNextRecord())
{
for (int i = 0; i < fieldCount; i++)
Console.Write(string.Format("{0} = {1};",
headers[i], csv[i]);
Console.WriteLine();
}
}
}</PRE>
这里面的意思好像也是直接把所有的数据读进内存然后处理,是吗?
TO:liujia_0421(SnowLover)
哇 都两颗星了还自称小弟 太谦虚喽~~
TO:按照这个意思我完全可以一次把300M数据读进内存咯,那也不同再每次读N行进行处理,直接处理岂不是更好?
不好意思,可能我理解有误..
再帮你关注一下..
TO:哇 都两颗星了还自称小弟 太谦虚喽~~
星多只能代表分多,不能说明什么问题..
确实刚转C#没多久,正在努力学习中..
请各位不吝指教,谢谢..
呵呵..
using System.IO;
using System.Text;
string pathSrc = .....;//原文件路径
string pathDes = .....;//目标文件路径
StreamReader sr = new StreamReader(pathSrc, Encoding.Default);//读取
StreamWriter sw = new StreamWirter(pathDes, true, Encoding.Default);//写入,使用追加模式
string temp;//临时字符串
string StringBuilder sb = new StringBuilder();
const int COUNT = 100;
int index = 0;
while((temp = sr.ReadLine) != null)//每次读一行,如果读出的字符串不为空
{
//在这里对temp进行处理
.....
//处理完了
sb.Append(temp);
if(++index >= COUNT)
{
sw.WriteLine(temp);
}
}
sr.Close();//释放资源
sw.Close();//释放资源
不好意思,上面那个有误,少了两行代码。
下面这个可以了
using System.IO;
using System.Text;
string pathSrc = .....;//原文件路径
string pathDes = .....;//目标文件路径
StreamReader sr = new StreamReader(pathSrc, Encoding.Default);//读取
StreamWriter sw = new StreamWirter(pathDes, true, Encoding.Default);//写入,使用追加模式
string temp;//临时字符串
string StringBuilder sb = new StringBuilder();//缓冲
const int COUNT = 100;//每次处理100行
int index = 0;
while((temp = sr.ReadLine) != null)//每次读一行,如果读出的字符串不为空
{
//在这里对temp进行处理
.....
//处理完了
sb.Append(temp);
if(++index >= COUNT)
{
sw.WriteLine(sh.ToString());
index = 0;//索引置零
sb.Length = 0;//缓冲置零
}
}
sr.Close();//释放资源
sw.Close();//释放资源
不好意思,还是有问题,上面的不会处理最后不足100行的数据。
另外,下面这个改了级算方法。
using System.IO;
using System.Text;
string pathSrc = .....;//原文件路径
string pathDes = .....;//目标文件路径
StreamReader sr = new StreamReader(pathSrc, Encoding.Default);//读取
StreamWriter sw = new StreamWirter(pathDes, true, Encoding.Default);//写入,使用追加模式
string temp;//临时字符串
string StringBuilder sb = new StringBuilder();//缓冲
const int COUNT = 1000000;//每次处理字符串长度最少1百万(大约在1M~2M字节之间)
while((temp = sr.ReadLine) != null)//每次读一行,如果读出的字符串不为空
{
//在这里对temp进行处理
.....
//处理完了
sb.Append(temp);
sb.Append(Environment.NewLine);//增加换行符
if(sb.Length >= COUNT)
{
sw.Write(sh.ToString());
sb.Length = 0;//缓冲置零
}
}
if(sb.Length > 0)//处理最后不足限制的字节
{
sw.Write(sh.ToString());
sb.Length = 0;//缓冲置零
}
sr.Close();//释放资源
sw.Close();//释放资源
楼上写的和我写的似乎也差不多,好像也不能满足楼主的要求..
都是高手,学习
纠正一下,楼主的这句应该是笔误?
sw.Write(sh.ToString());
——》sw.Write(sb.ToString());
对于IO操作,读和写时,具体是如何利用的内存,这些内在的东西我确实有点不大明白..
就像我上面写的..
static void Main(string[] args)
{
StreamReader sr = new StreamReader(new FileStream(@"C:\test\input.txt", FileMode.Open));
StreamWriter sw = new StreamWriter(new FileStream(@"C:\test\output.txt", FileMode.Append));
while (sr.Peek() > 0)
{
//计数器
int count = 0;
//用一个列表存储读出的N行,相当于一个缓冲
ArrayList list = new ArrayList();
while (sr.Peek() > 0 && count < 10)
{
//每次读10行
list.Add(sr.ReadLine());
count++;
}
//对读出的10行(有可能小于10),进行处理
foreach (string str in list )
{
//比如截取每个字符串的第一个字符,然后写入文件中
sw.Write(str.Substring(0, 1));
}
sw.Flush();
}
sr.Close();
sw.Close();
}
我最初我想法是,打开文件,读出文件中的N行再进行处理,放到一个ArrayList中,然后当计数达到N时,再对ArrayList进行操作,写入另外一个文件..
后来楼主说到和直接全部读入内存还是一个效果,想了一下,感觉也确实是..
对于如何读写大文本文件,我也查了些资料,没有一个明确的答案,建议用FileStream读取的比较多,可以用Read方法:
public override int Read (
[InAttribute] [OutAttribute] byte[] array,
int offset,
int count
)
当然也仅供参考..
对于IO操作读写时对内存的分配相关,如果哪位大哥有比较权威的资料,希望能提供给小弟,我也借此机会学习一下,谢谢..
也可能我的理解有误,小弟也刚步入C#学习不久,正在努力学习中..
liujia_0421(SnowLover) ( ) 信誉:100 Blog 2007-1-2 10:07:56 得分: 0
楼上写的和我写的似乎也差不多,好像也不能满足楼主的要求..
=====================================
还是我的程序结构容易理解一些,而且更省内存。
你的程序中使用了Peek以及记数器,有可能造成初学者的困惑。
而且你在程序中使用了ArrayList,单从效率角度讲,ArrayList内都是Object对象,就造成了每次访问对象时的拆箱装箱(box,unbox)操作,肯定降低了效率。
我使用的是StringBuilder,这是专门为大字符串操作所设计的类,对字符串操作进行过优化。
liujia_0421(SnowLover) ( ) 信誉:100 Blog 2007-1-2 10:07:56 得分: 0
楼上写的和我写的似乎也差不多,好像也不能满足楼主的要求..
=====================================
还是我的程序结构容易理解一些,而且更省内存。
你的程序中使用了Peek以及记数器,有可能造成初学者的困惑。
而且你在程序中使用了ArrayList,单从效率角度讲,ArrayList内都是Object对象,就造成了每次访问对象时的拆箱装箱(box,unbox)操作,肯定降低了效率。
我使用的是StringBuilder,这是专门为大字符串操作所设计的类,对字符串操作进行过优化。
liujia_0421(SnowLover) ( ) 信誉:100 Blog 2007-1-2 10:07:56 得分: 0
楼上写的和我写的似乎也差不多,好像也不能满足楼主的要求..
=====================================
还是我的程序结构容易理解一些,而且更省内存。
你的程序中使用了Peek以及记数器,有可能造成初学者的困惑。
而且你在程序中使用了ArrayList,单从效率角度讲,ArrayList内都是Object对象,就造成了每次访问对象时的拆箱装箱(box,unbox)操作,肯定降低了效率。
我使用的是StringBuilder,这是专门为大字符串操作所设计的类,对字符串操作进行过优化。
liujia_0421(SnowLover) ( ) 信誉:100 Blog 2007-1-2 10:07:56 得分: 0
楼上写的和我写的似乎也差不多,好像也不能满足楼主的要求..
=====================================
还是我的程序结构容易理解一些,而且更省内存。
你的程序中使用了Peek以及记数器,有可能造成初学者的困惑。
而且你在程序中使用了ArrayList,单从效率角度讲,ArrayList内都是Object对象,就造成了每次访问对象时的拆箱装箱(box,unbox)操作,肯定降低了效率。
我使用的是StringBuilder,这是专门为大字符串操作所设计的类,对字符串操作进行过优化。
liujia_0421(SnowLover) ( ) 信誉:100 Blog 2007-1-2 10:07:56 得分: 0
楼上写的和我写的似乎也差不多,好像也不能满足楼主的要求..
=====================================
还是我的程序结构容易理解一些,而且更省内存。
你的程序中使用了Peek以及记数器,有可能造成初学者的困惑。
而且你在程序中使用了ArrayList,单从效率角度讲,ArrayList内都是Object对象,就造成了每次访问对象时的拆箱装箱(box,unbox)操作,肯定降低了效率。
我使用的是StringBuilder,这是专门为大字符串操作所设计的类,对字符串操作进行过优化。
liujia_0421(SnowLover) ( ) 信誉:100 Blog 2007-1-2 10:07:56 得分: 0
楼上写的和我写的似乎也差不多,好像也不能满足楼主的要求..
=====================================
还是我的程序结构容易理解一些,而且更省内存。
你的程序中使用了Peek以及记数器,有可能造成初学者的困惑。
而且你在程序中使用了ArrayList,单从效率角度讲,ArrayList内都是Object对象,就造成了每次访问对象时的拆箱装箱(box,unbox)操作,肯定降低了效率。
我使用的是StringBuilder,这是专门为大字符串操作所设计的类,对字符串操作进行过优化。
liujia_0421(SnowLover) ( ) 信誉:100 Blog 2007-1-2 10:07:56 得分: 0
楼上写的和我写的似乎也差不多,好像也不能满足楼主的要求..
=====================================
还是我的程序结构容易理解一些,而且更省内存。
你的程序中使用了Peek以及记数器,有可能造成初学者的困惑。
而且你在程序中使用了ArrayList,单从效率角度讲,ArrayList内都是Object对象,就造成了每次访问对象时的拆箱装箱(box,unbox)操作,肯定降低了效率。
我使用的是StringBuilder,这是专门为大字符串操作所设计的类,对字符串操作进行过优化。
呵呵,谢谢mobydick(敌伯威|我排著队拿著爱的号码牌) 大哥的指点..
小弟初学C#,以后还请多多指教..
liujia_0421(SnowLover) ( ) 信誉:100 Blog 2007-1-2 10:07:56 得分: 0
楼上写的和我写的似乎也差不多,好像也不能满足楼主的要求..
=====================================
还是我的程序结构容易理解一些,而且更省内存。
你的程序中使用了Peek以及记数器,有可能造成初学者的困惑。
而且你在程序中使用了ArrayList,单从效率角度讲,ArrayList内都是Object对象,就造成了每次访问对象时的拆箱装箱(box,unbox)操作,肯定降低了效率。
我使用的是StringBuilder,这是专门为大字符串操作所设计的类,对字符串操作进行过优化。
。。。。。。我KAO,csdn有病,我重复发帖啊。
liujia_0421(SnowLover) ( ) 信誉:100 Blog 2007-01-02 21:05:58 得分: 0
呵呵,谢谢mobydick(敌伯威|我排著队拿著爱的号码牌) 大哥的指点..
小弟初学C#,以后还请多多指教..
==============================================
一起学习啊~~~
其实很简单,原理就是
1。打开文件 abc.txt 用来读,efg.txt用来保存处理后的数据
2。用字符流来一行一行读,你的目的是要从abc.txt中读到数据并处理,处理完后就直接写入另一个文件efj.txt,
3。关闭文件
如果你要分析的数据是以段落区分的,那你就用可能随机读取文件的流就行了,
别说你不知道用什么流啊!
那你要好好再学习学习了:)
引入临时文件,加异步来处理,要不容易使程序挂掉!
不过处理的数据最好不要在界面上显示,要不draw的时候也要死,我早就写过这个东西,一直实现不了,我就想UE(ultra edit)为什么处理大文件,几十M文件(再大的没试过),不管怎么批量编辑,都是那么快!真是好!看来VC++操作起来更有效率!
我都是这样的:写个框架吧:
string strInput=@"c:\file.input";
string strOutput=@"c:\file.input";
public void ReadLargeFile()
{
byte[] btsReadBuffer=new byte[1024*8];
//异步开始读取文件内容
FileStream fsRead=new FileStream(strInput,FileMode.Open,FileAccess.Read,FileShare.Write);
if(fsRead.CanRead)
{
fsRead.BeginRead(btsReadBuffer,0,btsReadBuffer.Length,new AsyncCallback(Callback_ReadFile),fsRead);
}
else
{
fsRead.Close();
throw new ApplicationException("Current Stream Couldn't Read!");
}
}
/// <summary>
/// 异步读取文件后所进行的操作
/// </summary>
/// <param name="ar"></param>
public void Callback_ReadFile(IAsyncResult ar)
{
FileStream fsRead=null;
FileStream fsWrite=null;
byte[] btsWriteBuffer=new byte[1024*8];
fsRead=(FileStream)ar.AsyncState;
int intReadCount=fsRead.EndRead(ar);
if(intReadCount>0)
{
string strReadContent=Encoding.Default.GetString(btsReadBuffer,0,btsReadBuffer.Length);
//这里放处理代码
//....
//...
btsWriteBuffer=Encoding.Default.GetBytes(strReadContent);
fsWrite=new FileStream(strOutput,FileMode.OpenOrCreate,FileAccess.Write,FileShare.Read);
if(fsWrite.CanWrite)
{
fsWrite.BeginWrite(btsWriteBuffer,0,btsWriteBuffer.Length,new AsyncCallback(Callback_WriteFile),fsWrite);
}
else
{
fsWrite.Close();
throw new ApplicationException("Current Stream Couldn't Write!");
}
}
else
{
fsRead.Close();
return;
}
fsRead.BeginRead(tbp1_GlobalData.btsBuffer,0,tbp1_GlobalData.btsBuffer.Length,new AsyncCallback(Callback_ReadFile),fsRead);
}
public void Callback_WriteFile(IAsyncResult ar)
{
FileStream fsWrite=null;
try
{
fsWrite=(FileStream)ar.AsyncState;
fsWrite.EndWrite(ar);
fsWrite.Close();
}
catch(Exception ex)
{
fsWrite.Close();
throw ex;
}
}
里面的一些抓错代码,全省略了,凑合看了!
对不住了,好多地方没有注释,不过各位肯定能看明白的,呵呵,这个只是框架而已!
整个过程,是对一个文件,边打开读取,边打开写,这就是为什么用FileShare.Read 或 FileShare.Write的原因了!
vb的做法:
FileOpen(1, "c:\1.txt", OpenMode.Input)
Dim str1 As String, i As Int16
For i = 0 To 10000
If EOF(1) Then Exit For
str1 = LineInput(1)
'处理一行文本的代码
Next
FileClose(1)
yulinlover(黑客我最菜)
20M搞定了么???呵呵~~
不过对于在RichTextBox里处理那个东西,还是不行,因为要不断的进行Draw,跟UE相比,慢得多了!
1. FS中2G以下的都能直接读,如果你觉得速度慢界面无响应,可以使用线程或者异步
2. 你是否选错了语言,我以前在X公司做数据统计,动不动就是G,T的数量级,当时用bash,根本没算法就是强行读,让*nix跑个几小时甚至一天
大家好热情啊,谢谢,
我按照liujia_0421(SnowLover)的想法尝试了一下,但没有分组处理,直接全部读进来然后处理,用了个300M左右的文件,发现不是传说中的死机,晕,莫非我过虑了?
按照shrinerain(圣影雨)提供的codeproject代码来看,他也是直接读进来的
莫非可以读没有问题?
想到了复制临时文件,一边读取(很少的行)一边删除(对应的行数)的办法…………
不知道对LZ会不会有帮助……
没细看所有回复,但每次读一行然后处理是没有问题的
系统不会傻到读一行就把内部缓冲区扔掉
决不可一次性读到内存!否则会使用虚存(页面交换文件,又写回硬盘了),导致频繁读写,效率极其低下!
StreamWriter 不能写大于4k的字符 怎么解决