Преобразование TMemoryStream в 'String' в Delphi 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?
8 ответов
Код, который у вас есть, излишне сложен, даже для более старых версий 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;
Это эквивалентно вашему исходному коду, но пропускает особые случаи.
Или, может быть, вы можете реорганизовать свой код для непосредственного использования TStringStream? Вы можете использовать его вместо TMemoryStream (они имеют одинаковый интерфейс), и вы можете "преобразовать" его в строку, просто вызвав myString:= myStringStream.DataString;
"Чистым" способом может быть:
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;
Я использую:
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.
Есть фактор под названием TStringStream
это сможет помочь вам.,.вы можете загрузить содержимое другого потока следующим образом:
var StringStream: TStringStream;
begin StringStream := TStringStream.Create('');
StringStream.CopyFrom(OtherStream, OtherStream.Size);
end;
Теперь вы можете войти в серию для типа String, такого как это: свойство data-string включает серию... но не пытайтесь делать это с большими объектами, например, если вы загружаете огромный файл в некоторый файловый поток, затем копируете это к вашему собственному потоку строк и приложите усилия, чтобы произвести это, потому что это организует много памяти!
надеюсь, это поможет
Я еще не обновился, но мое понимание:
NewCapacity := (M.Size + 1) * SizeOf(Char);
Вы можете преобразовать его в указатель символа нужного размера и просто назначить его:
procedure getMemoryStreamAsString( aMS_ : TMemoryStream );
var
ws : widestring; // in newer Delphi it can be string
ans : ansistring;
begin
ws := pwidechar( aMS_.memory );
// OR
ans := pansichar( aMS_.memory );
end;
используя старый добрый StringList
function StreamToString (Stream : TStream; Encoding : TEncoding) : string;
begin
var List := TStringList.Create;
try
List.LoadFromStream (Stream, Encoding);
Result := List.Text;
finally
List.Free;
end;
end;