Frage

Ich verwende Delphi7 (non-Unicode-VCL), ich brauche zu speichern viele Wide in einem TFileStream. Ich kann nicht TStringStream wie die (breit) Strings verwenden, werden mit binären Daten gemischt, wird das Format zu beschleunigen Laden projiziert und Schreiben der Daten ... Aber ich glaube, dass der Strom, wie ich bin Laden / die Saiten schreiben könnte sein, ein Engpass von meinem Code ...

zur Zeit schreibe ich Länge einer Zeichenkette, dann ist es von char char zu schreiben ... beim Laden, ich lade die Länge zuerst, dann Laden char von char ...

Also, was ist der schnellste Weg, um Wide TFileStream zu speichern und zu laden?

Vielen Dank im Voraus

War es hilfreich?

Lösung

Anstatt Lese- und Schreib ein Zeichen in einer Zeit, lesen und schreiben sie alle auf einmal:

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;

Nun, technisch gesehen, da WideString Windows BSTR ist, kann es eine ungerade Anzahl von Bytes enthalten. Die Length Funktion liest die Anzahl von Bytes und teilt durch zwei, so ist es möglich (wenn auch nicht wahrscheinlich), daß der Code über das letzte Byte abgeschnitten. Sie können diesen Code verwenden, anstatt:

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;

Inspiriert von mghie der Antwort haben meine Read und Write Anrufe mit ReadBuffer und WriteBuffer ersetzt. Letztere werden raise Ausnahmen, wenn sie nicht in der Lage, die angeforderte Anzahl von Bytes zu lesen oder schreiben.

Andere Tipps

Es gibt nichts Besonderes an Wide-Strings, um sie zu lesen und schreiben, so schnell wie möglich, Sie müssen so viel zu lesen und zu schreiben wie möglich in einem Rutsch:

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;

Wide enthält einen 'string' von WideChar ist, die Verwendung je 2 Bytes. Wenn Sie die UTF-16 (die Wide intern verwenden) Zeichenfolge in einer Datei gespeichert werden sollen, und in der Lage diese Datei wie Notepad in anderen Programmen zu verwenden, benötigen Sie ein Bytereihenfolgemarkierung zuerst:. #$FEFF

Wenn Sie das wissen, schriftlich wie folgt aussehen:

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

Lesen wie folgt aussehen:

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);

Sie können auch TFastFileStream zum Lesen der Daten oder Zeichenfolge verwenden, klebte ich das Gerät unter http://pastebin.com/ m6ecdc8c2 und eine Probe unter:

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.
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top