【问题标题】:saving a records containing a member of type string to a file (Delphi, Windows)将包含字符串类型成员的记录保存到文件(Delphi,Windows)
【发布时间】:2009-09-24 15:08:57
【问题描述】:

我的记录类似于:

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

简单。我选择将变量设置为字符串(而不是字符数组)的原因是我不知道这些字符串将有多长。它们可以是 1 个字符长、200 或 2000 个字符。 当然,当我尝试将记录保存到类型文件(...的文件)时,编译器会抱怨我必须为字符串指定大小。 有没有办法克服这个问题?还是一种将这些记录保存到无类型文件并仍然保持可搜索方式的方法?

请不要向我指出可能的解决方案,如果您知道解决方案,请发布代码。 谢谢

【问题讨论】:

  • 对不起,我的 XML 答案有点密集;我实际上正在参加两个会议(BASTA!和 DelphiLive!)。基本上,您需要做的事情非常简单:创建一个示例 XML 文件,然后启动 Delphi XML 数据绑定向导(从版本 6 开始在 Delphi 中可用),它将为您生成一个单元,该单元具有将 XML 映射到 Delphi 的接口和类对象,以及一些用于从文件中读取它们、创建新对象等的辅助函数。我的会话(请参阅我的答案中的链接)实际上包含此过程的大部分详细信息。
  • 请同时显示对我的回答的编辑:您也可以将数据存储在 DFM 文件中。
  • 重新上线 :-) 请确保您也下载了示例和幻灯片:这些是可读的:本页“Practical XML with Delphi”下的第三个链接:wiert.wordpress.com/2009/09/13/…

标签: windows delphi file records typed


【解决方案1】:

你不能用键入的文件来做到这一点。使用 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 版本编写的。在旧版本上,您可以将其简化很多。

【讨论】:

  • 谢谢。看看我能不能做这个。我需要更改很多代码。
  • 感谢您的直言不讳。代码为我指出了正确的解决方案。
【解决方案2】:

为什么不把它写成 XML 呢?请参阅我的会话“Practical XML with Delphi”了解如何开始。

另一种可能性是将您的记录放入从 TComponent 降级的类中,并在 DFM 文件中存储/检索您的数据。

This Stackoverflow entry 向您展示了如何做到这一点。

--杰罗恩

PS:抱歉,我的 XML 答案有点密集;我实际上正在参加两个会议(BASTA!DelphiLive! Germany)。

基本上你需要做的很简单:创建一个示例 XML 文件,然后启动 Delphi XML Data Binding Wizard(从版本 6 开始在 Delphi 中可用)。

该向导将为您生成一个单元,该单元具有将 XML 映射到 Delphi 对象的接口和类,以及一些用于从文件中读取它们、创建新对象等的辅助函数。我的会话(参见上面的第一个链接)实际上包含了这个过程的大部分细节。

以上链接是一个演示 Delphi XML 数据绑定向导用法的视频。

【讨论】:

  • 谢谢。所以现在我需要编写一个完整的 XML 解析函数。对于这样一个简单的任务(将字符串保存到文件中),工作量太大了。除非你有(按照我的要求)可以做到的示例代码。
  • +1 因为 Delphi 提供了 XML 接口(msxmldom、XMLDoc),恕我直言,它比实现自定义格式更容易。
  • 如果这么简单,请发布代码。我不明白为什么人们没有正确阅读这个问题。
  • XML 对于某些类型的数据来说一切都很好,但在这种情况下,我认为它有点矫枉过正。
  • @wonderer,a)我完全理解你的问题,b)我只在我想发布代码时才发布代码,而不是因为你这么说,c)我个人用数据库实现了这样的设施,比如 SQLite,因为可变长度记录需要更多努力才能提高效率。
【解决方案3】:

您可以使用两个不同的文件,一个仅以某种方便的方式存储字符串,另一个存储带有对字符串的引用的记录。这样,即使您不知道实际内容的大小,您仍然可以轻松访问记录文件。

(抱歉没有代码。)

【讨论】:

    【解决方案4】:
      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),但您说在这种情况下字符串超过 255 个字符,如果字符串超过 65535 个字符,则将 WORD 更改为 INTEGER

    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;
    

    【讨论】:

      【解决方案5】:

      您可以使用函数available in this Open Source unit

      它允许您将任何记录内容序列化为二进制,甚至包括其中的动态数组:

      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;
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-01-12
        • 2014-11-01
        • 1970-01-01
        • 2012-02-03
        相关资源
        最近更新 更多