(واسعة) سلسلة - تخزين في TFileStream، دلفي 7.ما هي أسرع طريقة؟
-
20-09-2019 - |
سؤال
أنا أستخدم Delphi7 (VCL غير Unicode)، ولست بحاجة لتخزين الكثير من WideStrings داخل TFileStream.لا يمكنني استخدام TStringStream حيث يتم خلط السلاسل (الواسعة) مع البيانات الثنائية، ومن المتوقع أن يؤدي التنسيق إلى تسريع تحميل البيانات وكتابتها ...ومع ذلك أعتقد أن الطريقة الحالية التي أقوم بها بتحميل/كتابة السلاسل قد تكون بمثابة عنق الزجاجة في الكود الخاص بي ...
أقوم حاليًا بكتابة طول سلسلة، ثم أكتبها حرفًا تلو الآخر ...أثناء التحميل، أقوم أولاً بتحميل الطول، ثم تحميل حرف تلو الآخر ...
إذًا، ما هي أسرع طريقة لحفظ وتحميل 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
هو ويندوز 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;
مستوحاة من جواب مغي, ، لقد حلت محل بلدي 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 تحتوي على 'سلسلة' من وWideChar، والتي تستخدم 2 بايت لكل منهما. إذا كنت ترغب في تخزين UTF-16 (التي تستخدم WideStrings داخليا) السلاسل في ملف، وتكون قادرة على استخدام هذا الملف في برامج أخرى مثل المفكرة، تحتاج لكتابة <لأ href = "http://unicode.org /faq/utf_bom.html "يختلط =" noreferrer نوفولو "> بايت ترتيب علامة أولا: #$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.