我从xml文件中读取UTF8内容,然后需要按需保存和重新加载。我正在从DavidFaffernan的AssignFile / Writeln / Readln转换为缓冲流:Buffered files (for faster disk access)
我有简单的新WriteLn和ReadLn程序,WriteLn工作,但我无法使ReadLn工作。
我对ReadLn的概念是处理:
新的WriteLn程序:
{ * New WriteLn * }
procedure TForm1.Button2Click(Sender: TObject);
var FileOut: TWriteCachedFileStream;
vText: string;
vUTF8Text: RawByteString;
begin
FileOut := TWriteCachedFileStream.Create('c:\tmp\file.txt');
try
vText := 'Delphi';
vUTF8Text := Utf8Encode(vText + sLineBreak);
FileOut.WriteBuffer(PAnsichar(vUTF8Text)^, Length(vUTF8Text));
vText := 'VB源码';
vUTF8Text := Utf8Encode(vText + sLineBreak);
FileOut.WriteBuffer(PAnsichar(vUTF8Text)^, Length(vUTF8Text));
vText := 'Java源码';
vUTF8Text := Utf8Encode(vText + sLineBreak);
FileOut.WriteBuffer(PAnsichar(vUTF8Text)^, Length(vUTF8Text));
finally
FileOut.Free;
end;
end;
但是Read有问题,因为它无法从文件中读取缓冲区。 TReadOnlyCachedFileStream的读取功能出错:
错误说:
"Project Project1.exe raised exception class $C0000005 with message 'access violation at 0x004069ca: write of address 0x00000010'."
function TReadOnlyCachedFileStream.Read(var Buffer; Count: Longint): Longint;
begin
...
Move(CachePtr^, BufferPtr^, NumOfBytesToCopy); { <- Error occurs here }
...
end;
这是我的ReadLn程序 - 无法正常工作,因为我无法解决错误:
{ * New ReadLn * }
procedure TForm1.Button3Click(Sender: TObject);
var FileIn: TReadOnlyCachedFileStream;
vLinesCounter, vCurrPos, vPrevPos: integer;
vBuffer: TBytes;
vUTF8Text, vPrevUTF8Text: string;
vFilesize,vBytesRead,vNumberOfBytes: Int64;
vCh: Char;
begin
vLinesCounter := 0;
FileIn := TReadOnlyCachedFileStream.Create('c:\tmp\file.txt');
try
vFilesize := FileIn.Size;
while FileIn.Position < vFilesize do
begin
vBytesRead:=FileIn.Read(vBuffer, 65536);
vNumberOfBytes := vNumberOfBytes + vBytesRead;
{1. Find Line break
2. Get Text from PrevPos to CurrPos-1
3. Save rest of buffer to add to first line of next Read buffer}
vCurrPos := 0; vPrevPos := 0;
while vCurrPos < vBytesRead do
begin
vCh:=Chr(vBuffer[vCurrPos]);
if (vCh = #13) Or (vCh = #10) then { is New line }
begin
if vPrevUTF8Text <> '' then
vUTF8Text := vPrevUTF8Text + TEncoding.UTF8.GetString(vBuffer, vPrevPos, vCurrPos - 1) { Add previous text that was not separet line}
else
vUTF8Text := TEncoding.UTF8.GetString(vBuffer, vPrevPos, vCurrPos - 1);
vPrevPos := vCurrPos; { Save Pos for next line }
Inc(vLinesCounter);
Memo1.Lines.Add(vUTF8Text);
end;
end;
{ save rest of text as start of next line }
if vCurrPos < Length(vBuffer) then
vPrevUTF8Text := TEncoding.UTF8.GetString(vBuffer, vPrevPos, vCurrPos - 1);
end;
finally
FileIn.Free
end;
Memo1.Lines.Add('Lines read: '+IntToStr(vLinesCounter));
end;
答案 0 :(得分:4)
RTL在System.Classes
单元中有自己的TStreamReader
和TStreamWriter
类,您应该让他们为您努力工作,例如:
procedure TForm1.Button2Click(Sender: TObject);
var
FileOut: TStreamWriter;
begin
FileOut := TStreamWriter.Create('c:\tmp\file.txt', False, TEncoding.UTF8);
try
FileOut.WriteLine('Delphi');
FileOut.WriteLine('VB源码');
FileOut.WriteLine('Java源码');
finally
FileOut.Free;
end;
end;
procedure TForm1.Button3Click(Sender: TObject);
var
FileIn: TStreamReader;
vLinesCounter: Integer;
begin
vLinesCounter := 0;
FileIn := TStreamReader.Create('c:\tmp\file.txt', True);
try
while not FileIn.EndOfStream do
begin
Memo1.Lines.Add(FileIn.ReadLine);
Inc(vLinesCounter);
end;
finally
FileIn.Free;
end;
Memo1.Lines.Add('Lines read: '+IntToStr(vLinesCounter));
end;
如果你想使用David的缓冲类(注意Delphi 10.1 Berlin增加了一个新的TBufferedFileStream
类),你仍然可以这样做,例如:
procedure TForm1.Button2Click(Sender: TObject);
var
FileStrm: TWriteCachedFileStream;
FileOut: TStreamWriter;
begin
FileStrm := TWriteCachedFileStream.Create('c:\tmp\file.txt');
try
FileOut := TStreamWriter.Create(FileStrm, TEncoding.UTF8);
try
FileOut.WriteLine('Delphi');
FileOut.WriteLine('VB源码');
FileOut.WriteLine('Java源码');
finally
FileOut.Free;
end;
finally
FileStrm.Free;
end;
end;
procedure TForm1.Button3Click(Sender: TObject);
var
FileStrm: TReadOnlyCachedFileStream;
FileIn: TStreamReader;
vLinesCounter: Integer;
begin
vLinesCounter := 0;
FileStrm := TReadOnlyCachedFileStream.Create('c:\tmp\file.txt');
try
FileIn := TStreamReader.Create(FileStrm, True);
try
while not FileIn.EndOfStream do
begin
Memo1.Lines.Add(FileIn.ReadLine);
Inc(vLinesCounter);
end;
finally
FileIn.Free;
end;
finally
FileStrm.Free;
end;
Memo1.Lines.Add('Lines read: '+IntToStr(vLinesCounter));
end;