web-dev-qa-db-fra.com

Conversion de TMemoryStream en 'String' dans Delphi 2009

Nous avions le code suivant avant 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;

Comment pourrions-nous convertir ce code pour prendre en charge Unicode maintenant avec Delphi 2009?

29
dmillam

Le code dont vous disposez est inutilement complexe, même pour les anciennes versions de Delphi. Pourquoi la récupération de la version chaîne d'un flux devrait-elle forcer la réallocation de la mémoire du flux, après tout?

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

Cela fonctionne dans toutes les versions de Delphi, pas seulement Delphi 2009. Il fonctionne lorsque le flux est vide sans cas particulier. SetString est une fonction sous-estimée.

Si le contenu de votre flux ne change pas en Unicode avec votre passage à Delphi 2009, vous devez utiliser cette fonction à la place:

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

Cela équivaut à votre code d'origine, mais ignore les cas spéciaux.

65
Rob Kennedy

Ou peut-être pouvez-vous refactoriser votre code pour utiliser directement un TStringStream directement? Vous pouvez l'utiliser à la place de TMemoryStream (ils ont la même interface) et vous pouvez le "convertir" en une chaîne en appelant simplement myString: = myStringStream.DataString;

16
John Thomas

Une façon plus "propre" pourrait être:

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;
12
Nick Hodges

J'utilise:

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;

Il a été testé avec Delphi XE7 uniquement.

4
Ivelin Nikolaev

Je n'ai pas encore mis à niveau, mais ma compréhension est la suivante:

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

Il existe un facteur appelé TStringStream qui pourra vous aider. . .vous pouvez charger le contenu d'un autre flux comme celui-ci:

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

Vous pouvez maintenant entrer dans la série pour un type de chaîne tel que celui-ci: La propriété de chaîne de données comprend la série ... mais n'essayez pas avec de gros objets comme dans le cas où vous chargez un fichier énorme dans un flux de fichiers, puis copiez ceci à votre propre chaîne de caractères et faites un effort pour le produire car cela arrange beaucoup de mémoire!

J'espère que cela pourra aider

2
Techpromint

Vous pouvez le lancer dans le pointeur de caractère de bonne taille et simplement l'affecter:

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;
1
The Bitman