2016-05-24 39 views
0

私のプロジェクトではXE8で作業していましたが、さまざまなタイプの変数とレコードを格納するカスタムプロジェクトファイルを保存して読み込む必要がありました。 最初は、この問題を解決するための私のアプローチはうまくいくように見えましたが、実際のプロジェクトでは問題があることが判明しました。Delphi:ファイルへの変数の書き込み/読み込み

「カテゴリー」の記録保存、ファイルを作成するための私の方法:

var 
SavingStream: TFileStream; 
     i,j: Integer; 
begin 
SavingStream:=TFileStream.Create('SAVE.test', fmCreate or fmOpenWrite or fmShareDenyWrite); 
SavingStream.Position:=0; 
i:=Length(Categories);     **// storing size of an array in a temp variable** 
SavingStream.WriteBuffer(i,SizeOf(i)); **// for some reason i couldn't save it directly** 
for i:=0 to Length(Categories)-1 do 
    begin   
    **{ String }** 
    SavingStream.WriteBuffer(Categories[i].Name,SizeOf(Categories[i].Name)); 
    **{ Integer }** 
    SavingStream.WriteBuffer(Categories[i].ID,SizeOf(Categories[i].ID)); 
    **{ Boolean }** 
    SavingStream.WriteBuffer(Categories[i].Default,SizeOf(Categories[i].Default)) 
    **{ Same routine for dynamic array }** 
    j:=Length(Categories[i].ChildrenType); 
    SavingStream.WriteBuffer(j,SizeOf(j)); 
    if j>=1 then for j:=0 to Length(Categories[i].ChildrenType)-1 do SavingStream.WriteBuffer(Categories[i].ChildrenType[j],SizeOf(Categories[i].ChildrenType[j])); 
    end; 
end; 

し、それを読んで:主な問題の

var 
SavingStream: TFileStream; 
     i,j: Integer; 
begin 
try 
SavingStream.ReadBuffer(i,SizeOf(i)); 
SetLength(Categories,i); 
for i:=0 to Length(Categories)-1 do 
    begin 
    SavingStream.ReadBuffer(Categories[i].Name,SizeOf(Categories[i].Name));  
    SavingStream.ReadBuffer(Categories[i].ID,SizeOf(Categories[i].ID));   
    SavingStream.ReadBuffer(Categories[i].Default,SizeOf(Categories[i].Default)); 
    SavingStream.ReadBuffer(j,SizeOf(j)); 
    SetLength(Categories[i].ChildrenType,j); 
    if j>=1 then for j:=0 to Length(Categories[i].ChildrenType)-1 do SavingStream.ReadBuffer(Categories[i].ChildrenType[j],SizeOf(Categories[i].ChildrenType[j])); 
    end; 
finally 
SavingStream.Free; 
end; 

一つは、私は完全に理解していないということですこのメソッドの背後にある論理。 SizeOf(i)は、基本的に、それ以外の同種のファイルの特定の部分をとり、それを変数の値として取ることを言います。しかし、私はどのように可変サイズの文字列と配列を格納するのですか?レコード自体のサイズを制限することは可能ですが、制限したくない特定の文字列変数があります。

したがって、私が使用しているメソッドが適切であるかどうかのアドバイスが必要です私はそれが私の特定の場合に働くようにすることができます。おそらく、この情報を保存するためのよりよい方法がありますか?私は画像を含むさまざまな種類の膨大な種類を保存しなければならないことを覚えておいてください。

Thxです。

+0

SerializeをJSONに。または類似。現時点では、ディスクへのポインタを書いています。メモリアドレスを書き込む。あなたがそれらを読んでも何も意味しません。このようなコードを書く前に、より多くの根本的な作業を行う必要があります。ポインタと、文字列の実装方法などを理解する必要があります。 –

答えて

3

文字列のような可変長データを、他のメモリアドレスへのポインタを含まないフラット形式にシリアル化する必要があります。

はこのような何かを試してみてください:

procedure WriteIntegerToStream(Stream: TStream; Value: Integer); 
begin 
    Stream.WriteBuffer(Value, Sizeof(Value)); 
end; 

procedure WriteBooleanToStream(Stream: TStream; Value: Boolean); 
begin 
    Stream.WriteBuffer(Value, Sizeof(Value)); 
end; 

procedure WriteStringToStream(Stream: TStream; const Value: String); 
var 
    S: UTF8String; 
    Len: Integer; 
begin 
    S := UTF8String(Value); 
    Len := Length(S); 
    Stream.WriteBuffer(Len, Sizeof(Len)); 
    Stream.WriteBuffer(PAnsiChar(S)^, Len); 
end; 

var 
    SavingStream: TFileStream; 
    i, j: Integer; 
begin 
    SavingStream := TFileStream.Create('SAVE.test', fmCreate or fmOpenWrite or fmShareDenyWrite); 
    try 
    WriteIntegerToStream(SavingStream, Length(Categories)); 
    for i := 0 to Length(Categories)-1 do 
    begin   
     WriteStringToStream(SavingStream, Categories[i].Name); 
     WriteIntegerToStream(SavingStream, Categories[i].ID); 
     WriteBooleanToStream(SavingStream, Categories[i].Default); 
     WriteIntegerToStream(SavingStream, Length(Categories[i].ChildrenType)); 
     for j := 0 to Length(Categories[i].ChildrenType)-1 do 
     begin 
     // write ChildrenType[j] data to SavingStream as needed... 
     end; 
    finally 
    SavingStream.Free; 
    end; 
end; 

バックファイルを読み込むときに、あなたが似たような操作を行うことができます。

function ReadIntegerFromStream(Stream: TStream): Integer; 
begin 
    Stream.ReadBuffer(Result, Sizeof(Result)); 
end; 

function ReadBooleanFromStream(Stream: TStream): Boolean; 
begin 
    Stream.ReadBuffer(Result, Sizeof(Result)); 
end; 

function ReadStringFromStream(Stream: TStream): String; 
var 
    S: UTF8String; 
    Len: Integer; 
begin 
    Stream.ReadBuffer(Len, Sizeof(Len)); 
    SetLength(S, Len); 
    Stream.ReadBuffer(PAnsiChar(S)^, Len); 
    Result := String(S); 
end; 

var 
    LoadingStream: TFileStream; 
    i, j: Integer; 
begin 
    LoadingStream := TFileStream.Create('SAVE.test', fmOpenRead or fmShareDenyWrite); 
    try 
    i := ReadIntegerFromStream(LoadingStream); 
    SetLength(Categories, i); 
    for i := 0 to Length(Categories)-1 do 
    begin 
     Categories[i].Name := ReadStringFromStream(LoadingStream); 
     Categories[i].ID := ReadIntegerFromStream(LoadingStream); 
     Categories[i].Default := ReadBooleanFromStream(LoadingStream); 
     j := ReadIntegerFromStream(LoadingStream); 
     SetLength(Categories[i].ChildrenType, j); 
     for j := 0 to Length(Categories[i].ChildrenType)-1 do 
     begin 
     // read ChildrenType[j] data from LoadingStream as needed... 
     end; 
    end; 
    finally 
    LoadingStream.Free; 
    end; 
end; 
関連する問題