(宽)字符串 - 存储在TFileStream,Delphi 7中.最快的方法是什么?

mig*_*jek 6 delphi widestring tfilestream

我正在使用Delphi7(非unicode VCL),我需要在TFileStream中存储大量WideStrings.我不能使用TStringStream,因为(宽)字符串与二进制数据混合,预计格式会加速加载和写入数据...但是我相信当前我正在加载/写入字符串的方式可能是我的代码的瓶颈......

目前我正在写一个字符串的长度,然后用char写它char ...加载时,首先我加载长度,然后加载char的char ...

那么,将WideString保存并加载到TFileStream的最快方法是什么?

提前致谢

Rob*_*edy 6

不是一次读写一个字符,而是一次读取和写入所有字符:

procedure WriteWideString(const ws: WideString; stream: TStream);
var
  nChars: LongInt;
begin
  nChars := Length(ws);
  stream.WriteBuffer(nChars, SizeOf(nChars);
  if nChars > 0 then
    stream.WriteBuffer(ws[1], nChars * SizeOf(ws[1]));
end;

function ReadWideString(stream: TStream): WideString;
var
  nChars: LongInt;
begin
  stream.ReadBuffer(nChars, SizeOf(nChars));
  SetLength(Result, nChars);
  if nChars > 0 then
    stream.ReadBuffer(Result[1], nChars * SizeOf(Result[1]));
end;
Run Code Online (Sandbox Code Playgroud)

现在,从技术上讲,既然WideString是Windows BSTR,它可以包含奇数个字节.该Length函数读取字节数并除以2,因此可能(尽管不太可能)上面的代码将切断最后一个字节.您可以使用此代码:

procedure WriteWideString(const ws: WideString; stream: TStream);
var
  nBytes: LongInt;
begin
  nBytes := SysStringByteLen(Pointer(ws));
  stream.WriteBuffer(nBytes, SizeOf(nBytes));
  if nBytes > 0 then
    stream.WriteBuffer(Pointer(ws)^, nBytes);
end;

function ReadWideString(stream: TStream): WideString;
var
  nBytes: LongInt;
  buffer: PAnsiChar;
begin
  stream.ReadBuffer(nBytes, SizeOf(nBytes));
  if nBytes > 0 then begin
    GetMem(buffer, nBytes);
    try
      stream.ReadBuffer(buffer^, nBytes);
      Result := SysAllocStringByteLen(buffer, nBytes)
    finally
      FreeMem(buffer);
    end;
  end else
    Result := '';
end;
Run Code Online (Sandbox Code Playgroud)

灵感来自Mghie的回答,已经取代了我ReadWrite与电话ReadBufferWriteBuffer.如果后者无法读取或写入请求的字节数,则会引发异常.


mgh*_*hie 6

宽字符串没有什么特别之处,尽可能快地读取和写入它们,你需要尽可能多地读写:

procedure TForm1.Button1Click(Sender: TObject);
var
  Str: TStream;
  W, W2: WideString;
  L: integer;
begin
  W := 'foo bar baz';

  Str := TFileStream.Create('test.bin', fmCreate);
  try
    // write WideString
    L := Length(W);
    Str.WriteBuffer(L, SizeOf(integer));
    if L > 0 then
      Str.WriteBuffer(W[1], L * SizeOf(WideChar));

    Str.Seek(0, soFromBeginning);
    // read back WideString
    Str.ReadBuffer(L, SizeOf(integer));
    if L > 0 then begin
      SetLength(W2, L);
      Str.ReadBuffer(W2[1], L * SizeOf(WideChar));
    end else
      W2 := '';
    Assert(W = W2);
  finally
    Str.Free;
  end;
end;
Run Code Online (Sandbox Code Playgroud)