(와이드) 문자열 - 델파이 7. Tfilestream에 저장 7. 가장 빠른 방법은 무엇입니까?
-
20-09-2019 - |
문제
Delphi7 (비 유니 코드 VCL)을 사용하고 있는데, 많은 widestrings를 tfilestream 안에 저장해야합니다. (와이드) 문자열이 바이너리 데이터와 혼합되어 TStringstream을 사용할 수 없습니다. 형식은 로딩 속도를 높이고 데이터를 작성하도록 투영됩니다 ... 그러나 현재의 방식으로로드/쓰기는 끈이 될 수 있다고 생각합니다. 내 코드의 병목 현상 ...
현재 나는 줄의 길이를 쓰고 char로 숯을 쓰고있다 ...로드하는 동안 먼저 길이를로드 한 다음 숯으로 숯을로드하고있다 ...
그렇다면 tfilestream에 widestring을 저장하고로드하는 가장 빠른 방법은 무엇입니까?
미리 감사드립니다
해결책
한 번에 하나의 캐릭터를 읽고 쓰지 않고 한 번에 모두 읽고 쓰십시오.
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
창문입니다 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;
에서 영감을 받다 Mghie의 대답, 내 대체했습니다 Read
그리고 Write
전화 ReadBuffer
그리고 WriteBuffer
. 후자는 요청 된 바이트 수를 읽거나 쓸 수없는 경우 예외를 제기합니다.
다른 팁
넓은 문자열에 대한 특별한 것은 없습니다. 가능한 한 빨리 읽고 쓰기 위해 최대한 읽고 쓸 필요가 있습니다.
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;
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);
데이터 또는 문자열을 읽기 위해 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.