I read UTF8 content from xml files and then need to save and re-load on demand. I'm converting from AssignFile/Writeln/Readln to Buffered streams by David Heffernan: Buffered files (for faster disk access)
I have simple new WriteLn and ReadLn procedures, WriteLn works, but I can't make ReadLn work.
My concept for ReadLn is to process:
- Read buffer
- Find Line break
- Get Text from PrevPos to CurrPos-1
- Save rest of buffer to add to first line of next Read buffer
New WriteLn procedure:
{ * 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;
But have problems with Read because it fails to Read to buffer from file. Error occurs in Read function of TReadOnlyCachedFileStream:
Error says:
"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;
And here is my ReadLn procedure - not working as I can't get through the error:
{ * 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;
 
     
    