6

Delphi7(非ユニコードVCL)を使用しているので、TFileStream内に多くのWideStringを格納する必要があります。(ワイド)文字列がバイナリデータと混合されているため、TStringStreamを使用できません。この形式は、データの読み込みと書き込みを高速化すると予測されています...ただし、文字列の読み込み/書き込みの現在の方法は、私のコードのボトルネック..。

現在、文字列の長さを書き込んでから、charごとに書き込んでいます...ロード中に、最初に長さをロードし、次にcharごとにロードしています...

では、WideStringをTFileStreamに保存してロードする最速の方法は何ですか?

前もって感謝します

4

4 に答える 4

6

一度に1文字ずつ読み書きするのではなく、一度にすべてを読み書きします。

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;

技術的にWideStringは、はWindowsであるため、奇数のバイトBSTRを含めることができます。この関数はバイト数を読み取り、2で除算するため、上記のコードが最後のバイトを切り捨てる可能性があります(可能性は低いですが)。代わりに次のコードを使用できます。Length

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;

Mghieの答えに触発されて、myReadWritecallsをReadBufferandに置き換えましたWriteBuffer。後者は、要求されたバイト数の読み取りまたは書き込みができない場合に例外を発生させます。

于 2009-08-30T15:38:10.580 に答える
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;
于 2009-08-30T15:39:19.750 に答える
2

WideStringsには、それぞれ2バイトを使用するWideCharの「文字列」が含まれています。UTF-16(WideStringsが内部で使用する)文字列をファイルに格納し、このファイルをメモ帳などの他のプログラムで使用できるようにする場合は、最初にバイト順マーク#$FEFFを書き込む必要があります。

あなたがこれを知っているなら、書くことは次のようになります:

Stream1.Write(WideString1[1],Length(WideString)*2); //2=SizeOf(WideChar)

読書は次のようになります。

Stream1.Read(WideChar1,2);//assert returned 2 and WideChar1=#$FEFF
SetLength(WideString1,(Stream1.Size div 2)-1);
Stream1.Read(WideString1[1],(Stream1.Size div 2)-1);
于 2009-08-30T16:10:49.610 に答える
1

データや文字列を読み取るためにTFastFileStreamを使用することもできます。ユニットをhttp://pastebin.com/m6ecdc8c2に貼り付け、以下のサンプルを示します。

program Project36;

{$APPTYPE CONSOLE}

uses
  SysUtils, Classes,
  FastStream in 'FastStream.pas';

const
  WideNull: WideChar = #0;

procedure WriteWideStringToStream(Stream: TFileStream; var Data: WideString);
var
  len: Word;
begin
  len := Length(Data);
  // Write WideString length
  Stream.Write(len, SizeOf(len));
  if (len > 0) then
  begin
    // Write WideString
    Stream.Write(Data[1], len * SizeOf(WideChar));
  end;
  // Write null termination
  Stream.Write(WideNull, SizeOf(WideNull));
end;

procedure CreateTestFile;
var
  Stream: TFileStream;
  MyString: WideString;
begin
  Stream := TFileStream.Create('test.bin', fmCreate);
  try
    MyString := 'Hello World!';
    WriteWideStringToStream(Stream, MyString);

    MyString := 'Speed is Delphi!';
    WriteWideStringToStream(Stream, MyString);
  finally
    Stream.Free;
  end;
end;

function ReadWideStringFromStream(Stream: TFastFileStream): WideString;
var
  len: Word;
begin
  // Read length of WideString
  Stream.Read(len, SizeOf(len));
  // Read WideString
  Result := PWideChar(Cardinal(Stream.Memory) + Stream.Position);
  // Update position and skip null termination
  Stream.Position := Stream.Position + (len * SizeOf(WideChar)) + SizeOf(WideNull);
end;

procedure ReadTestFile;
var
  Stream: TFastFileStream;

  my_wide_string: WideString;
begin
  Stream := TFastFileStream.Create('test.bin');
  try
    Stream.Position := 0;
    // Read WideString
    my_wide_string := ReadWideStringFromStream(Stream);
    WriteLn(my_wide_string);
    // Read another WideString
    my_wide_string := ReadWideStringFromStream(Stream);
    WriteLn(my_wide_string);
  finally
    Stream.Free;
  end;
end;

begin
  CreateTestFile;
  ReadTestFile;
  ReadLn;
end.
于 2009-08-30T18:52:51.827 に答える