Reputation: 373
We had the following code prior to 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;
How might we convert this code to support Unicode now with Delphi 2009?
Upvotes: 33
Views: 88007
Reputation: 49
using good old 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;
Upvotes: 0
Reputation: 1329
You can cast it into the right sized character pointer and just simple assign it:
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;
Upvotes: 1
Reputation: 21
There's a factor called TStringStream
that will be able to assist you. . .you can load the contents of another flow like that:
var StringStream: TStringStream;
begin StringStream := TStringStream.Create('');
StringStream.CopyFrom(OtherStream, OtherStream.Size);
end;
You can now get into the series for a String kind such as this: The data-string property comprises the series... but do not try so with large objects such as in the event that you load a huge file to some filestream then copy this to your own stringstream and make an effort to produce it cause it arranges a lot of memory!
Hope that helps
Upvotes: 2
Reputation: 9083
I have not upgraded yet, but my understanding is:
NewCapacity := (M.Size + 1) * SizeOf(Char);
Upvotes: 2
Reputation: 6762
I use:
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;
It has been tested with Delphi XE7 only.
Upvotes: 6
Reputation: 163247
The code you have is unnecessarily complex, even for older Delphi versions. Why should fetching the string version of a stream force the stream's memory to be reallocated, after all?
function MemoryStreamToString(M: TMemoryStream): string;
begin
SetString(Result, PChar(M.Memory), M.Size div SizeOf(Char));
end;
That works in all Delphi versions, not just Delphi 2009. It works when the stream is empty without any special case. SetString
is an under-appreciated function.
If the contents of your stream aren't changing to Unicode with your switch to Delphi 2009, then you should use this function instead:
function MemoryStreamToString(M: TMemoryStream): AnsiString;
begin
SetString(Result, PAnsiChar(M.Memory), M.Size);
end;
That's equivalent to your original code, but skips the special cases.
Upvotes: 73
Reputation: 17108
A "cleaner" way might be:
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;
Upvotes: 19
Reputation: 4135
Or perhaps you can refactor your code to use directly a TStringStream directly? You can use it instead of TMemoryStream (they have the same interface) and you can 'convert' it to a string by simply calling myString := myStringStream.DataString;
Upvotes: 23