2010-12-07 9 views
7

que tienen las siguientes estructuras en Delphi 2009:¿Cómo puedo guardar una matriz dinámica en FileStream en Delphi?

type 
    IndiReportIndi = record 
    IndiName: string; 
    NameNum: integer; 
    ReportIndiName: string; 
    end; 

var 
    XRefList: array of IndiReportIndi; 

donde XRefList es una matriz dinámica.

Quiero guardar XRefList en FileStream. ¿Cómo hago eso Y incluyo todas las cadenas IndiName y ReportIndiName para que todos puedan recuperarse nuevamente cuando más tarde cargue desde ese FileStream?

+1

Desde diciembre de 2010, no es un nuevo [unidad de Open Source] (http://blog.synopse.info/post/2011/03/12/TDynArray-and-Record-compare/load/save-using-fast-RTTI) que vale la pena considerar para serializar registros o matrices dinámicas (con muchas más funciones que la serialización), que funciona para Delphi 5 hasta XE2. –

Respuesta

6

Uso: http://code.google.com/p/kblib/

type 
    IndiReportIndi = record 
    IndiName: string; 
    NameNum: integer; 
    ReportIndiName: string; 
    end; 

    TXRefList = array of IndiReportIndi; 

var 
    XRefList: TXRefList; 

Para guardar XRefList todo para transmitir su uso:

TKBDynamic.WriteTo(lStream, XRefList, TypeInfo(TXRefList)); 

Para cargar de nuevo:

TKBDynamic.ReadFrom(lStream, XRefList, TypeInfo(TXRefList)); 
+0

Parece una rutina realmente agradable. Gracias por mencionarlo. – lkessler

10
type 
    IndiReportIndi = record 
    IndiName: string; 
    NameNum: integer; 
    ReportIndiName: string; 
    procedure SaveToStream(Stream: TStream); 
    procedure LoadFromStream(Stream: TStream); 
    end; 

type 
    TXRefList = array of IndiReportIndi; 

function LoadString(Stream: TStream): string; 
var 
    N: Integer; 

begin 
    Result:= ''; 
    Stream.ReadBuffer(N, SizeOf(Integer)); 
    if N > 0 then begin 
    SetLength(Result, N); 
// Stream.ReadBuffer(Result[1], N * SizeOf(Char)); 
// fast version - see comment by A.Bouchez 
    Stream.ReadBuffer(Pointer(Result)^, N * SizeOf(Char)); 
    end; 
end; 

procedure SaveString(Stream: TStream; const S: string); 
var 
    N: Integer; 

begin 
    N:= Length(S); 
    Stream.WriteBuffer(N, SizeOf(Integer)); 
    if N > 0 then 
// Stream.WriteBuffer(S[1], N * SizeOf(Char)); 
// fast version - see comment by A.Bouchez 
    Stream.WriteBuffer(Pointer(S)^, N * SizeOf(Char)); 
end; 

procedure IndiReportIndi.LoadFromStream(Stream: TStream); 
var 
    S: string; 

begin 
    IndiName:= LoadString(Stream); 
    Stream.ReadBuffer(NameNum, SizeOf(Integer)); 
    ReportIndiName:= LoadString(Stream); 
end; 

procedure IndiReportIndi.SaveToStream(Stream: TStream); 
begin 
    SaveString(Stream, IndiName); 
    Stream.WriteBuffer(NameNum, SizeOf(Integer)); 
    SaveString(Stream, ReportIndiName); 
end; 

function LoadXRefList(Stream: TStream): TXRefList; 
var 
    N: Integer; 
    I: Integer; 

begin 
    Stream.ReadBuffer(N, SizeOf(Integer)); 
    if N <= 0 then Result:= nil 
    else begin 
    SetLength(Result, N); 
    for I:= 0 to N - 1 do 
     Result[I].LoadFromStream(Stream); 
    end; 
end; 

procedure SaveXRefList(Stream: TStream; const List: TXRefList); 
var 
    N: Integer; 
    I: Integer; 

begin 
    N:= Length(List); 
    Stream.WriteBuffer(N, SizeOf(Integer)); 
    for I:= 0 to N - 1 do 
    List[I].SaveToStream(Stream); 
end; 
+2

Podría haber usado el puntero (Resultado)^en lugar del Resultado [1] en LoadString y el puntero (S)^en lugar de S [1] en SaveString, porque guardará una llamada a UniqueString(). LoadString también podría ser un poco más rápido si se codifica con result: = '' en todos los casos, luego SetLength (Result, N) si N> 0: no habrá reasignación de memoria (con un movimiento lento), sino que una cadena finalizará nueva asignación (que es más rápida). –

+0

Use un TReader/TWriter para simplificar la escritura de tipos de datos estándar. En lugar de Stream.WriteBuffer (N, SizeOf (Entero)); simplemente escribiría Write.WriteInger (N) y N: = Reader.ReadInteger ;. También tienen soporte para cadenas y variantes, y el código es mucho más legible. Acabas de duplicar el código que Delphi ya tiene. –

+0

@ldsandon: la implementación de TReader/TWriter depende de la versión de Delphi y puede cambiar. No es deseable confiar en los métodos TReader/TWriter para implementar su propia serialización de datos. – kludg

5
var 
    S: TStream; 
    W: TWriter; 
    A: array of IndiReportIndi; 
    E: IndiReportIndi; 
    ... 
begin 
    S := nil; 
    W := nil; 
    try 
    S := TFileStream.Create(...); 
    W := TWriter.Create(S); 
    W.WriteInteger(Length(A)); 
    for E in A do 
    begin 
     W.WriteString(E.IndiName); 
     W.WriteInteger(E.NameNum); 
     W.WriteString(E.ReportIndiName); 
    end; 
    finally 
    W.Free; 
    S.Free 
    end; 
end; 

leer esos datos que utiliza un pisador y ReadInteger/ReadString.

+0

Gracias ldsandon. Agradable y limpio y simple. +1. – lkessler

0

Sólo por la respuesta que se precisa:

considerar tomar un vistazo a la TDynArray envoltorio, que es capaz de serializar cualquier grabar en binarios, y también en/desde matrices dinámicas.

Hay muchos métodos como TList, incluso nuevos métodos (como búsqueda hash o binaria).

Muy optimizado para la velocidad y el uso del disco, funciona para Delphi 5 hasta XE2 - y de código abierto.

Ver también How to store dynamic arrays in a TList?

0

solución probada:

procedure TForm1.FormCreate(Sender: TObject); 
VAR Stream: TFileStream; 
    R: IndyRecordIndy; 
begin 
Stream:= TFileStream.Create; 
TRY 
    //put rec in stream 
    Stream.WriteBuffer(R, SizeOf(R)); 

    //restore record from stram 
    Stream.Position := 0; 
    Stream.ReadBuffer(R, Stream.Size); 
FINALLY 
    FreeAndNil(Stream); 
END; 
end 



; 
Cuestiones relacionadas