(واسعة) سلسلة - تخزين في TFileStream، دلفي 7.ما هي أسرع طريقة؟

StackOverflow https://stackoverflow.com/questions/1354092

  •  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.
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top