文字列型のメンバーを含むレコードをファイルに保存する (Delphi、Windows)

StackOverflow https://stackoverflow.com/questions/1472325

質問

次のようなレコードがあります。

type
  TNote = record
    Title : string;
    Note  : string;
    Index : integer;
  end;

単純。変数を (文字の配列ではなく) 文字列として設定することにした理由は、それらの文字列の長さがどれくらいになるかわからないからです。長さは 1 文字、200 文字、または 2000 文字にすることができます。もちろん、レコードをタイプファイル (... のファイル) に保存しようとすると、コンパイラは文字列にサイズを指定する必要があると警告します。これを克服する方法はありますか?それとも、それらのレコードを型指定されていないファイルに保存し、検索可能な方法を維持する方法でしょうか?

私に指摘しないでください 可能な解決策, 、解決策を知っている場合は、コードを投稿してください。ありがとう

役に立ちましたか?

解決

あなたは入力されたファイルでそれを行うことはできません。 TFileStreamで、このような何かを試してみてください。

type
   TStreamEx = class helper for TStream
   public
      procedure writeString(const data: string);
      function readString: string;
      procedure writeInt(data: integer);
      function readInt: integer;
  end;

function TStreamEx.readString: string;
var
   len: integer;
   iString: UTF8String;
begin
   self.readBuffer(len, 4);
   if len > 0 then
   begin
      setLength(iString, len);
      self.ReadBuffer(iString[1], len);
      result := string(iString);
   end;
end;

procedure TStreamEx.writeString(const data: string);
var
   len: cardinal;
   oString: UTF8String;
begin
   oString := UTF8String(data);
   len := length(oString);
   self.WriteBuffer(len, 4);
   if len > 0 then
      self.WriteBuffer(oString[1], len);
end;

function TStreamEx.readInt: integer;
begin
   self.readBuffer(result, 4);
end;

procedure TStreamEx.writeInt(data: integer);
begin
   self.WriteBuffer(data, 4);
end;

type
  TNote = record
    Title : string;
    Note  : string;
    Index : integer;
    procedure Save(stream: TStream);
  end;

procedure TNote.Save(stream: TStream);
var
   temp: TMemoryStream;
begin
   temp := TMemoryStream.Create;
   try
      temp.writeString(Title);
      temp.writeString(Note);
      temp.writeInt(Index);
      temp.seek(0, soFromBeginning);
      stream.writeInt(temp.size);
      stream.copyFrom(temp, temp.size);
   finally
      temp.Free;
   end;
end;

私はあなたにロード手順を残しておきます。同じ基本的な考え方が、それは一時ストリームを必要はありません。各エントリの前のレコードサイズで、あなたはそれを読んで、あなたが特定のレコード#探しの代わりに、全体のことを読んでいる場合はスキップするようにどこまで知ることができます。

編集:これは、Unicode文字列を使用するDelphiのバージョンのために特別に書かれました。古いバージョンでは、あなたはそれをかなり簡略化することができます。

他のヒント

これを XML として書き出してみてはいかがでしょうか。私のセッションをご覧ください。」Delphi を使用した実践的な XML「これを始める方法について。」

もう 1 つの可能性は、レコードを TComponent から派生したクラスに作成し、データを DFM ファイルに保存/取得することです。

この Stackoverflow エントリ その方法を示します。

--ジェローン

追伸:申し訳ありませんが、私の XML の回答は少し複雑でした。実は私は 2 つのカンファレンスに参加するため出張中です (バスタ! そして デルフィライブ!ドイツ).

基本的にやるべきことは非常に簡単です。サンプル XML ファイルを作成し、 Delphi XML データ バインディング ウィザード (Delphi バージョン 6 以降で利用可能)。

このウィザードは、XML を Delphi オブジェクトにマッピングするインターフェイスとクラス、およびファイルからの読み取りや新しいオブジェクトの作成などのためのいくつかのヘルパー関数を備えたユニットを生成します。私のセッション (上記の最初のリンクを参照) には、実際にはこのプロセスの詳細のほとんどが含まれています。

上記のリンクは、Delphi XML データ バインディング ウィザードの使用法を示すビデオです。

あなたは、文字列を参照して2つの異なるファイル、単にいくつかの便利な方法で文字列を格納し1、他店の記録で仕事ができます。そうすれば、あなたはまだあなたが実際のコンテンツのサイズがわからないにもかかわらず、簡単にアクセスするために、レコードのファイルを持っています。

(なしコードを申し訳ありません。)

  TNote = record
    Title : string;
    Note  : string;
    Index : integer;
  end;

のように変換することができます。

  TNote = record
    Title : string[255];
    Note  : string[255];
    Index : integer;
  end;

とStream.writebuffer(ANodeVariable、はsizeof(TNODE)を使用しますが、その後、

INTEGERにWORDを変更する文字列は65535文字の上に行けば文字列が、この場合には255を超える文字を行く得ることを言いました
type
TNodeHeader=Record
  TitleLen,
  NoteLen: Word;
end;

(* this is for writing a TNode *)
procedure saveNodetoStream(theNode: TNode; AStream: TStream);
var
  header: TNodeHeader;
  pStr: PChar;
begin
  ...
  (* writing to AStream which should be initialized before this *)
  Header.TitleLen := Length(theNode.Title);
  header.NodeLen := Length(theNode.Note);
  AStream.WriteBuffer(Header, sizeof(TNodeHeader);
  (* save strings *)
  PStr := PChar(theNode.Title);
  AStream.writeBuffer(PStr^, Header.TitleLen);
  PStr := PChar(theNode.Note);
  AStream.writebuffer(PStr^, Header.NoteLen);
  (* save index *)
  AStream.writebuffer(theNode.Index, sizeof(Integer));
end;
(* this is for reading a TNode *)
function readNode(AStream: TStream): TNode;
var
  header: THeader
  PStr: PChar;
begin
  AStream.ReadBuffer(Header, sizeof(TNodeHeader);
  SetLength(Result.Title, Header.TitleLen);
  PStr := PChar(Result.Title);
  AStream.ReadBuffer(PStr^, Header.TitleLen);
  SetLength(Result.Note, Header.NoteLen);
  PStr := PChar(Result.Note);
  AStream.ReadBuffer(PStr^, Header.NoteLen);
  AStream.ReadBuffer(REsult.Index, sizeof(Integer)(* 4 bytes *);
end;

機能を使用できます このオープンソース単元で利用可能.

これにより、以下の動的配列も含め、あらゆるレコードの内容をバイナリにシリアル化できます。

type
  TNote = record
    Title : string;
    Note  : string;
    Index : integer;
  end;

var
  aSave: TRawByteString;
  aNote, aNew: TNote;
begin
  // create some content
  aNote.Title := 'Title';
  aNote.Note := 'Note';
  aNote.Index := 10;
  // serialize the content
  aSave := RecordSave(aNote,TypeInfo(TNote));
  // unserialize the content
  RecordLoad(aNew,pointer(aSave),TypeInfo(TNote));
  // check the content
  assert(aNew.Title = 'Title');
  assert(aNew.Note = 'Note');
  assert(aNew.Index = 10);
end;
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top