2009-04-09 14 views
26

Tuvimos el siguiente código antes de Delphi 2009:conversión de TMemoryStream a 'Cadena' en Delphi 2009

<span style="font: 10pt Courier New;"><span class="pas1-reservedword">function</span><span class="pas1-space"> </span><span class="pas1-identifier">MemoryStreamToString(M:</span><span class="pas1-space"> </span><span class="pas1-identifier">TMemoryStream):</span><span class="pas1-space"> </span><span class="pas1-reservedword">String</span><span class="pas1-symbol">; 
</span><span class="pas1-reservedword">var 
</span><span class="pas1-space"> </span><span class="pas1-identifier">NewCapacity:</span><span class="pas1-space"> </span><span class="pas1-identifier">Longint; 
</span><span class="pas1-reservedword">begin 
</span><span class="pas1-space"> </span><span class="pas1-reservedword">if</span><span class="pas1-space"> </span><span class="pas1-symbol">(M.Size</span><span class="pas1-space"> </span><span class="pas1-symbol">=</span><span class="pas1-space"> </span><span class="pas1-number">0)</span><span class="pas1-space"> </span><span class="pas1-reservedword">or</span><span class="pas1-space"> </span><span class="pas1-symbol">(M.Memory</span><span class="pas1-space"> </span><span class="pas1-symbol">=</span><span class="pas1-space"> </span><span class="pas1-reservedword">nil</span><span class="pas1-symbol">)</span><span class="pas1-space"> </span><span class="pas1-reservedword">then 
</span><span class="pas1-space"> </span><span class="pas1-identifier">Result:=</span><span class="pas1-space"> </span><span class="pas1-string">'' 
</span><span class="pas1-space"> </span><span class="pas1-reservedword">else 
</span><span class="pas1-space"> </span><span class="pas1-reservedword">begin 
</span><span class="pas1-space"> </span><span class="pas1-reservedword">if</span><span class="pas1-space"> </span><span class="pas1-identifier">TMemoryStreamProtected(M).Capacity</span><span class="pas1-space"> </span><span class="pas1-symbol">=</span><span class="pas1-space"> </span><span class="pas1-identifier">M.Size</span><span class="pas1-space"> </span><span class="pas1-reservedword">then 
</span><span class="pas1-space"> </span><span class="pas1-reservedword">begin 
</span><span class="pas1-space">  </span><span class="pas1-identifier">NewCapacity:=</span><span class="pas1-space"> </span><span class="pas1-identifier">M.Size+1; 
</span><span class="pas1-space">  </span><span class="pas1-identifier">TMemoryStreamProtected(M).Realloc(NewCapacity); 
</span><span class="pas1-space"> </span><span class="pas1-reservedword">end</span><span class="pas1-symbol">; 
</span><span class="pas1-space"> </span><span class="pas1-identifier">NullString(M.Memory^)[M.Size]:=</span><span class="pas1-space"> </span><span class="pas1-character">#0; 
</span><span class="pas1-space"> </span><span class="pas1-identifier">Result:=</span><span class="pas1-space"> </span><span class="pas1-identifier">StrPas(M.Memory); 
</span><span class="pas1-space"> </span><span class="pas1-reservedword">end</span><span class="pas1-symbol">; 
</span><span class="pas1-reservedword">end</span><span class="pas1-symbol">; 
</span></span> 

¿Cómo podríamos convertir este código para ser compatible con Unicode ahora con Delphi 2009?

Respuesta

62

El código que tiene es innecesariamente complejo, incluso para versiones anteriores de Delphi. ¿Por qué la búsqueda de la versión de cadena de una secuencia obliga a reasignar la memoria de la secuencia, después de todo?

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

que funciona en todas las versiones de Delphi, no sólo Delphi 2009. Funciona cuando la corriente está vacía sin ningún caso especial. SetString es una función poco apreciada.

Si el contenido de su corriente no están cambiando a Unicode con su interruptor para Delphi 2009, entonces debería usar esta función en lugar:

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

Eso es equivalente a su código original, pero se salta los casos especiales .

+1

He hecho muchas cosas de la memoria Delphi, pero no había escuchado sobre SetString, siempre usé SetLength (dest, length) y Move (src, @ (dest [1]), length); que SetString también (llama a _LStrFromPCharLen) –

+0

encasillado en un PC no debería crear ningún problema. –

+0

Pointer es compatible con todo. La única razón por la que necesitaría escribir es si el compilador tuvo problemas con la resolución de sobrecarga. –

2

no he actualizado todavía, pero mi entendimiento es:

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

O quizás usted puede refactorizar el código para utilizar directamente un TStringStream directamente? Puede usarlo en lugar de TMemoryStream (tienen la misma interfaz) y puede 'convertirlo' a una cadena simplemente llamando a myString: = myStringStream.DataString;

+1

De hecho, eso fue lo primero que se me ocurrió. ¿Por qué no crear un TStringStream, cargar la corriente de memoria en él y devolver la cadena de datos? –

12

Una forma "limpia" podría ser:

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; 
+0

"aStream.Position: = 0" no es necesario, como si llamara a "SS.CopyFrom (aStream, 0)", posicionará la fuente en 0 y obtendrá su tamaño para usted. – jonjbar

+0

De acuerdo, es suficiente. –

+6

Tiene que tener cuidado con 'TStringStream' en D2009 +, ya que es' TEncoding'-aware ahora. 'CopyFrom()' copiará los bytes sin formato de la fuente 'TStream' tal como está, pero el getter de la propiedad' DataString' decodificará esos bytes usando lo que 'TEncoding' se pase al' TStringStream' constructor ('TEncoding.Default' o 'TEncoding.UTF8' por defecto, IIRC). Entonces, si la codificación 'TStream' no coincide con la codificación' TStringStream', obtendrá pérdida/corrupción de datos. –

3

que utilizo:

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; 

Se ha probado sólo con Delphi XE7.

+0

'TBytes' es una matriz dinámica.El primer parámetro de 'ReadBuffer()' es un 'var' sin tipo. Debe desreferenciar los' TBytes' para obtener la dirección de memoria correcta para pasar a 'ReadBuffer()', por ejemplo: 'ReadBuffer (StringBytes [0], .. .) 'o más seguro' ReadBuffer (PByte (StringBytes) ^, ...) 'cuando' Size' es 0. –

Cuestiones relacionadas