others - 在Delphi 7 TFileStream中,宽字符串存储最快的方式是什么?

我正在使用Delphi7(非Unicode VCL),需要在TFileStream内部存储很多(宽)字符串。

将WideString保存到TFileStream的最快方法是什么?

时间:

不要一次读取和写入一个字符,而是同时读取和写入它们:


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,它可以包含奇数个字节,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;



对于宽字符串没有什么特别的,要尽可能快地读写它们,你需要尽可能在一个过程中地读写:


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;




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



你还可以使用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.



...