从文件流中读数据的问题(100分)

  • 主题发起人 主题发起人 ow
  • 开始时间 开始时间
O

ow

Unregistered / Unconfirmed
GUEST, unregistred user!
我用TFileStream打开了一个文件,然后从里面逐个读出字符串,读字符串的代码如下:
function MyReadln(Stream: TStream): String; // may raise an EReadError exception when end of file occurs
var
InWord: Boolean;
C: Char;
begin
InWord := False;
Result := '';
while Stream.Read(C, 1) > 0 do
begin
if C > ' ' then
begin
Result := Result + C;
if not InWord then InWord := True;
end
else if InWord then Break;
end;
end;
但是运行时发现读的速度非常慢,远远低于用如下语句实现的速度(大约慢10倍左右):
Assign(MyFile, FileName);
Reset(MyFile);
Readln(MyFile, AStr);
请问这是什么原因?
 
一个一个读当然慢了,不如一下子全部读入,然后再处理。
 
试过用TMemoryStream.CopyFrom(Stream)一次性载入以后再从TMemoryStream中读,一样慢。
 
何必要转手?既然你是打开文件,可以直接:
var
f: TMemroyStream;
begin
f := TMemoryStream.Create;
f.LoadFromFile('c:/abc.txt');
//然后直接在 f 这个 memorystream 里面解决
....
f.Free;
end;
 
我根本得不到文件名的说,传进来的参数就是一个TStream类的实例。
 
适一下下面的代码
function MyReadln(Stream: TStream): String;
var
Buffer: PChar;
i:integer;
begin
Result := '';
i:=sizeof(Stream);
GetMem(Buffer, i);
try
Stream.Read(Buffer, i);
Result := Buffer;
finally
FreeMem(Buffer);
SourceStream.Free;
end;
end;
 
可以直接用一个strings配合memorystream读入,你试试
var
sList: TStrings;
str:String;
begin
sList := TStringList.Create;
try
sr.Position:=0;
sList.LoadFromStream(sr);//sr is a stream
str:=sList.GetText;
ShowMessage(str);
finally
sList.Free;
end;
end;
 
to menxin:
不行啊,TStringList读入时是以行为单位的,行内的字符串(以空格分隔)它就不
在Parse了。
 
那就直接找空格呀,也不至于一个一个读啊

 
//TStringList读入时是以行为单位的,行内的字符串(以空格分隔)它就不在Parse了。
你一行一行处理总比一个一个处理来得快的多吧
 
改成用TStringList来处理,速度还是比较慢,载入5M的文件所需时间是原来用
Readln/Writeln的4倍。
 
reset(x)缺省每次读出128字节数据。Stream.Read(C, 1) 每次只读一个字节。
 
Result := '';
while Stream.Read(C, 1) > 0 do //1..慢!
begin
if C > ' ' then
begin
Result := Result + C; //2..慢!——每次都要重新分配一个更大的内存,然后把原来的Copy过去
if not InWord then InWord := True;
...

解决方案:
1- 用一个16K的Buffer,每次16K的读取/处理。
2- 加一个ResultBuffer(16K),用于存放处理结果,每处理16K的信息之后,一次性将其添加到Result之后。
然后再处理下16K数据...
处理时还要增加一个辅助变量:Location:Integer;用于表示ResultBuffer中的当前写入位置,
它在每次从Stream读取信息时被初始化,每写一个字符就增加1。
 
搭个便车: 如何将一个个的记录读到对应类型的文件流中去???
 
creation-zy说的对。
要找空格可以使用pos函数,故而不要逐个字符读取。
另外,也可以设计一个算法,定长读出规定的长度然后做个整理
如:
clssFileStream.Read(pchar(strAString)^,255 ) ;
处理字符
判断strAString最后一个是否是' ';
根据上面的判断定位clssFileStream.的文件指针
循环

另外,对于大文件的处理,直接的IO是不合适的。尽量使用内存印象的方式。

祝你好运!
:)
 
如果写入的就一个WORD类型,怎么读出来
var a:pword;
FileStream.Read(a,2);这样是读步出来的
 
panyongze的例子应改为:
function MyReadln(Stream: TStream): String;
var
Buffer: PChar;
i:integer;
begin
Result := '';
i:=sizeof(Stream);
GetMem(Buffer, i);
try
Stream.Read(Buffer[red]^[/red], i);
Result := Buffer;
finally
FreeMem(Buffer);
SourceStream.Free;
end;
end;
 
能回答上面我说的问题马
 
如果写入的就一个WORD类型,怎么读出来
var a:pword;
FileStream.Read(a,2);这样是读步出来的

FileStream.Read(a^, 2)
 
FileStream.Read(a^, 2) 同样单步执行的时候也读步出来
 

Similar threads

S
回复
0
查看
3K
SUNSTONE的Delphi笔记
S
S
回复
0
查看
2K
SUNSTONE的Delphi笔记
S
I
回复
0
查看
709
import
I
后退
顶部