Преобразование TMemoryStream в 'String' в Delphi 2009 - PullRequest
26 голосов
/ 09 апреля 2009

До Delphi 2009 у нас был следующий код:

function MemoryStreamToString(M : TMemoryStream): String;
var
    NewCapacity: Longint;
begin
    if (M.Size = > 0) or (M.Memory = nil) then
       Result:= '' 
    else
    begin
       if TMemoryStreamProtected(M).Capacity = M.Size then
       begin
           NewCapacity:= M.Size+1;
           TMemoryStreamProtected(M).Realloc(NewCapacity);
       end;
       NullString(M.Memory^)[M.Size]:= #0;
       Result:= StrPas(M.Memory);
    end;
end;

Как мы можем преобразовать этот код для поддержки Unicode сейчас с Delphi 2009?

Ответы [ 6 ]

63 голосов
/ 09 апреля 2009

Код, который у вас есть, излишне сложен, даже для более старых версий Delphi. Зачем, в конце концов, выборка строковой версии потока принудительно перераспределяет память потока?

function MemoryStreamToString(M: TMemoryStream): string;
begin
  SetString(Result, PChar(M.Memory), M.Size div SizeOf(Char));
end;

Это работает во всех версиях Delphi, не только в Delphi 2009. Это работает, когда поток пуст без какого-либо особого случая. SetString - недооцененная функция.

Если содержимое вашего потока не меняется на Unicode при переключении на Delphi 2009, вам следует использовать эту функцию вместо:

function MemoryStreamToString(M: TMemoryStream): AnsiString;
begin
  SetString(Result, PAnsiChar(M.Memory), M.Size);
end;

Это эквивалентно вашему исходному коду, но пропускает особые случаи.

16 голосов
/ 09 апреля 2009

Или, возможно, вы можете изменить свой код, чтобы напрямую использовать TStringStream? Вы можете использовать его вместо TMemoryStream (они имеют одинаковый интерфейс), и вы можете «преобразовать» его в строку, просто вызвав myString: = myStringStream.DataString;

12 голосов
/ 09 апреля 2009

«Чище» может быть:

function StreamToString(aStream: TStream): string;
var
  SS: TStringStream;
begin
  if aStream <> nil then
  begin
    SS := TStringStream.Create('');
    try
      SS.CopyFrom(aStream, 0);  // No need to position at 0 nor provide size
      Result := SS.DataString;
    finally
      SS.Free;
    end;
  end else
  begin
    Result := '';
  end;
end;
4 голосов
/ 31 декабря 2014

Я использую:

function StreamToString(const Stream: TStream; const Encoding: TEncoding): string;
var
  StringBytes: TBytes;
begin
  Stream.Position := 0;
  SetLength(StringBytes, Stream.Size);
  Stream.ReadBuffer(StringBytes, Stream.Size);
  Result := Encoding.GetString(StringBytes);
end;

Протестировано только с Delphi XE7.

2 голосов
/ 10 октября 2018

Есть фактор под названием TStringStream, который сможет вам помочь. , Вы можете загрузить содержимое другого потока следующим образом:

var StringStream: TStringStream; 
begin StringStream := TStringStream.Create(''); 
StringStream.CopyFrom(OtherStream, OtherStream.Size); 
end;

Теперь вы можете войти в серию для типа String, такого как это: свойство data-string включает в себя серию ... но не пытайтесь делать это с большими объектами, например, если вы загружаете огромный файл в какой-то filestream, затем скопируйте его в свой собственный поток строк и постарайтесь его создать, потому что он занимает много памяти!

Надеюсь, что поможет

2 голосов
/ 09 апреля 2009

Я еще не обновился, но я понимаю:

NewCapacity := (M.Size + 1) * SizeOf(Char);
...