大文本文件的读取与写入

问题:现有一大文本文件预计300M,无法直接读入内存处理,现在的想法是每次从这个文件中读取n行进行处理,处理后其中的部分行需要再存入一个新的文本,估计这个新的文本也有几十M,那我怎么才能不把整个文件读入内存还能够每次读取n行呢?怎样才能都将n行的处理结果追加到新文本中呢?
最后祝大家新年快乐!
[153 byte] By [daci-daci] at [2008-1-9]
# 1
我晕,什么文本这么大啊?
每次读取N行貌似也不好处理,这么大个文本不能拆开么?
ustbwuyi at 2007-10-19 > top of Msdn China Tech,.NET技术,C#...
# 2
现在的问题是能够处理就可以,不追求速度!我每次读N行也就是为了拆开处理阿
daci-daci at 2007-10-19 > top of Msdn China Tech,.NET技术,C#...
# 3
新年快乐
# 4
我晕...天下无敌巨无霸的文本 300M~~~~
# 5
不大了,我刚才看到人家一下读1.5g进去,也不知道怎么读的
daci-daci at 2007-10-19 > top of Msdn China Tech,.NET技术,C#...
# 6
300M...
我经常处理几个G的文本文件...

StreamReader读就好了
shrinerain-圣影雨 at 2007-10-19 > top of Msdn China Tech,.NET技术,C#...
# 7
to shrinerain(圣影雨),俄的神阿,能贴点code吗?是一次子就读进去然后进行处理吗?
daci-daci at 2007-10-19 > top of Msdn China Tech,.NET技术,C#...
# 8
观注+学习
# 9
自己UP
daci-daci at 2007-10-19 > top of Msdn China Tech,.NET技术,C#...
# 10
http://www.Codefund.cn/develop/Article/25/25337.shtm
# 11
你的意思是每一行都有一个处理结果吗?

liujia_0421-SnowLover at 2007-10-19 > top of Msdn China Tech,.NET技术,C#...
# 12
小弟学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();
}
liujia_0421-SnowLover at 2007-10-19 > top of Msdn China Tech,.NET技术,C#...
# 13
在Codeproject上搜索CSVReader,是你想要的东西...
shrinerain-圣影雨 at 2007-10-19 > top of Msdn China Tech,.NET技术,C#...
# 14
TO liujia_0421(SnowLover):按照这个意思我完全可以一次把300M数据读进内存咯,那也不同再每次读N行进行处理,直接处理岂不是更好?
daci-daci at 2007-10-19 > top of Msdn China Tech,.NET技术,C#...
# 15
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>
这里面的意思好像也是直接把所有的数据读进内存然后处理,是吗?
daci-daci at 2007-10-19 > top of Msdn China Tech,.NET技术,C#...
# 16
TO:liujia_0421(SnowLover)
哇 都两颗星了还自称小弟 太谦虚喽~~
# 17
TO:按照这个意思我完全可以一次把300M数据读进内存咯,那也不同再每次读N行进行处理,直接处理岂不是更好?

不好意思,可能我理解有误..

再帮你关注一下..
liujia_0421-SnowLover at 2007-10-19 > top of Msdn China Tech,.NET技术,C#...
# 18
TO:哇 都两颗星了还自称小弟 太谦虚喽~~

星多只能代表分多,不能说明什么问题..

确实刚转C#没多久,正在努力学习中..

请各位不吝指教,谢谢..

呵呵..
liujia_0421-SnowLover at 2007-10-19 > top of Msdn China Tech,.NET技术,C#...
# 19
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();//释放资源
# 20
曾经打开过一个600m的文本,当时死掉
terryshi-terryshi at 2007-10-19 > top of Msdn China Tech,.NET技术,C#...
# 21
不好意思,上面那个有误,少了两行代码。
下面这个可以了
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();//释放资源
# 22
不好意思,还是有问题,上面的不会处理最后不足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();//释放资源
# 23
楼上写的和我写的似乎也差不多,好像也不能满足楼主的要求..
liujia_0421-SnowLover at 2007-10-19 > top of Msdn China Tech,.NET技术,C#...
# 24
都是高手,学习
纠正一下,楼主的这句应该是笔误?
sw.Write(sh.ToString());
——》sw.Write(sb.ToString());
xjjdanran-何流 at 2007-10-19 > top of Msdn China Tech,.NET技术,C#...
# 25
对于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
)

当然也仅供参考..
liujia_0421-SnowLover at 2007-10-19 > top of Msdn China Tech,.NET技术,C#...
# 26
对于IO操作读写时对内存的分配相关,如果哪位大哥有比较权威的资料,希望能提供给小弟,我也借此机会学习一下,谢谢..

也可能我的理解有误,小弟也刚步入C#学习不久,正在努力学习中..
liujia_0421-SnowLover at 2007-10-19 > top of Msdn China Tech,.NET技术,C#...
# 27
liujia_0421(SnowLover) ( ) 信誉:100 Blog 2007-1-2 10:07:56 得分: 0

楼上写的和我写的似乎也差不多,好像也不能满足楼主的要求..

=====================================
还是我的程序结构容易理解一些,而且更省内存。
你的程序中使用了Peek以及记数器,有可能造成初学者的困惑。
而且你在程序中使用了ArrayList,单从效率角度讲,ArrayList内都是Object对象,就造成了每次访问对象时的拆箱装箱(box,unbox)操作,肯定降低了效率。
我使用的是StringBuilder,这是专门为大字符串操作所设计的类,对字符串操作进行过优化。
# 28
liujia_0421(SnowLover) ( ) 信誉:100 Blog 2007-1-2 10:07:56 得分: 0

楼上写的和我写的似乎也差不多,好像也不能满足楼主的要求..

=====================================
还是我的程序结构容易理解一些,而且更省内存。
你的程序中使用了Peek以及记数器,有可能造成初学者的困惑。
而且你在程序中使用了ArrayList,单从效率角度讲,ArrayList内都是Object对象,就造成了每次访问对象时的拆箱装箱(box,unbox)操作,肯定降低了效率。
我使用的是StringBuilder,这是专门为大字符串操作所设计的类,对字符串操作进行过优化。
# 29
liujia_0421(SnowLover) ( ) 信誉:100 Blog 2007-1-2 10:07:56 得分: 0

楼上写的和我写的似乎也差不多,好像也不能满足楼主的要求..

=====================================
还是我的程序结构容易理解一些,而且更省内存。
你的程序中使用了Peek以及记数器,有可能造成初学者的困惑。
而且你在程序中使用了ArrayList,单从效率角度讲,ArrayList内都是Object对象,就造成了每次访问对象时的拆箱装箱(box,unbox)操作,肯定降低了效率。
我使用的是StringBuilder,这是专门为大字符串操作所设计的类,对字符串操作进行过优化。
# 30
liujia_0421(SnowLover) ( ) 信誉:100 Blog 2007-1-2 10:07:56 得分: 0

楼上写的和我写的似乎也差不多,好像也不能满足楼主的要求..

=====================================
还是我的程序结构容易理解一些,而且更省内存。
你的程序中使用了Peek以及记数器,有可能造成初学者的困惑。
而且你在程序中使用了ArrayList,单从效率角度讲,ArrayList内都是Object对象,就造成了每次访问对象时的拆箱装箱(box,unbox)操作,肯定降低了效率。
我使用的是StringBuilder,这是专门为大字符串操作所设计的类,对字符串操作进行过优化。
# 31
liujia_0421(SnowLover) ( ) 信誉:100 Blog 2007-1-2 10:07:56 得分: 0

楼上写的和我写的似乎也差不多,好像也不能满足楼主的要求..

=====================================
还是我的程序结构容易理解一些,而且更省内存。
你的程序中使用了Peek以及记数器,有可能造成初学者的困惑。
而且你在程序中使用了ArrayList,单从效率角度讲,ArrayList内都是Object对象,就造成了每次访问对象时的拆箱装箱(box,unbox)操作,肯定降低了效率。
我使用的是StringBuilder,这是专门为大字符串操作所设计的类,对字符串操作进行过优化。
# 32
liujia_0421(SnowLover) ( ) 信誉:100 Blog 2007-1-2 10:07:56 得分: 0

楼上写的和我写的似乎也差不多,好像也不能满足楼主的要求..

=====================================
还是我的程序结构容易理解一些,而且更省内存。
你的程序中使用了Peek以及记数器,有可能造成初学者的困惑。
而且你在程序中使用了ArrayList,单从效率角度讲,ArrayList内都是Object对象,就造成了每次访问对象时的拆箱装箱(box,unbox)操作,肯定降低了效率。
我使用的是StringBuilder,这是专门为大字符串操作所设计的类,对字符串操作进行过优化。
# 33
liujia_0421(SnowLover) ( ) 信誉:100 Blog 2007-1-2 10:07:56 得分: 0

楼上写的和我写的似乎也差不多,好像也不能满足楼主的要求..

=====================================
还是我的程序结构容易理解一些,而且更省内存。
你的程序中使用了Peek以及记数器,有可能造成初学者的困惑。
而且你在程序中使用了ArrayList,单从效率角度讲,ArrayList内都是Object对象,就造成了每次访问对象时的拆箱装箱(box,unbox)操作,肯定降低了效率。
我使用的是StringBuilder,这是专门为大字符串操作所设计的类,对字符串操作进行过优化。
# 34
呵呵,谢谢mobydick(敌伯威|我排著队拿著爱的号码牌) 大哥的指点..

小弟初学C#,以后还请多多指教..
liujia_0421-SnowLover at 2007-10-19 > top of Msdn China Tech,.NET技术,C#...
# 35
mark
caitian6 at 2007-10-19 > top of Msdn China Tech,.NET技术,C#...
# 36
liujia_0421(SnowLover) ( ) 信誉:100 Blog 2007-1-2 10:07:56 得分: 0

楼上写的和我写的似乎也差不多,好像也不能满足楼主的要求..

=====================================
还是我的程序结构容易理解一些,而且更省内存。
你的程序中使用了Peek以及记数器,有可能造成初学者的困惑。
而且你在程序中使用了ArrayList,单从效率角度讲,ArrayList内都是Object对象,就造成了每次访问对象时的拆箱装箱(box,unbox)操作,肯定降低了效率。
我使用的是StringBuilder,这是专门为大字符串操作所设计的类,对字符串操作进行过优化。
# 37
。。。。。。我KAO,csdn有病,我重复发帖啊。
# 38
liujia_0421(SnowLover) ( ) 信誉:100 Blog 2007-01-02 21:05:58 得分: 0

呵呵,谢谢mobydick(敌伯威|我排著队拿著爱的号码牌) 大哥的指点..

小弟初学C#,以后还请多多指教..

==============================================
一起学习啊~~~
# 40
学习学习 很好
dychenyi at 2007-10-19 > top of Msdn China Tech,.NET技术,C#...
# 41
mark
simonllf-simon at 2007-10-19 > top of Msdn China Tech,.NET技术,C#...
# 42
其实很简单,原理就是
1。打开文件 abc.txt 用来读,efg.txt用来保存处理后的数据
2。用字符流来一行一行读,你的目的是要从abc.txt中读到数据并处理,处理完后就直接写入另一个文件efj.txt,
3。关闭文件

如果你要分析的数据是以段落区分的,那你就用可能随机读取文件的流就行了,

别说你不知道用什么流啊!
那你要好好再学习学习了:)
evane1890 at 2007-10-19 > top of Msdn China Tech,.NET技术,C#...
# 43
引入临时文件,加异步来处理,要不容易使程序挂掉!
不过处理的数据最好不要在界面上显示,要不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;
}
}

里面的一些抓错代码,全省略了,凑合看了!
# 44
对不住了,好多地方没有注释,不过各位肯定能看明白的,呵呵,这个只是框架而已!

整个过程,是对一个文件,边打开读取,边打开写,这就是为什么用FileShare.Read 或 FileShare.Write的原因了!
# 45
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)
# 46
yulinlover(黑客我最菜)
20M搞定了么???呵呵~~
Qiao_caT-乔乔 at 2007-10-19 > top of Msdn China Tech,.NET技术,C#...
# 47
搞定了,刚开始为了那个问题,搞了N久!
# 48

不过对于在RichTextBox里处理那个东西,还是不行,因为要不断的进行Draw,跟UE相比,慢得多了!
# 49
关注。。
min_jie-止戈 at 2007-10-19 > top of Msdn China Tech,.NET技术,C#...
# 50
几天不见,都顶到这里来啦?

再顶下..
liujia_0421-SnowLover at 2007-10-19 > top of Msdn China Tech,.NET技术,C#...
# 51
1. FS中2G以下的都能直接读,如果你觉得速度慢界面无响应,可以使用线程或者异步
2. 你是否选错了语言,我以前在X公司做数据统计,动不动就是G,T的数量级,当时用bash,根本没算法就是强行读,让*nix跑个几小时甚至一天
Red_angelX-八戒 at 2007-10-19 > top of Msdn China Tech,.NET技术,C#...
# 52
大家好热情啊,谢谢,
我按照liujia_0421(SnowLover)的想法尝试了一下,但没有分组处理,直接全部读进来然后处理,用了个300M左右的文件,发现不是传说中的死机,晕,莫非我过虑了?
按照shrinerain(圣影雨)提供的codeproject代码来看,他也是直接读进来的
莫非可以读没有问题?
daci-daci at 2007-10-19 > top of Msdn China Tech,.NET技术,C#...
# 53
想到了复制临时文件,一边读取(很少的行)一边删除(对应的行数)的办法…………
不知道对LZ会不会有帮助……
xomix-小狼羔 at 2007-10-19 > top of Msdn China Tech,.NET技术,C#...
# 55
顶这个,^_^,
tjuyyf-皮皮 at 2007-10-19 > top of Msdn China Tech,.NET技术,C#...
# 56
没细看所有回复,但每次读一行然后处理是没有问题的
系统不会傻到读一行就把内部缓冲区扔掉
决不可一次性读到内存!否则会使用虚存(页面交换文件,又写回硬盘了),导致频繁读写,效率极其低下!
viena-维也纳N02 at 2007-10-19 > top of Msdn China Tech,.NET技术,C#...
# 57
星,三角,红色,绿色,分别代表什么意思?
# 58
我才是一个绿三角!!
# 59
StreamWriter 不能写大于4k的字符 怎么解决
ayun00-阿云 at 2007-10-19 > top of Msdn China Tech,.NET技术,C#...