【问题标题】:How Can I Save a Dynamic Array to a FileStream in Delphi?如何在 Delphi 中将动态数组保存到 FileStream?
【发布时间】:2010-12-07 04:33:15
【问题描述】:

我在 Delphi 2009 中有以下结构:

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

var
  XRefList: array of IndiReportIndi;

其中 XRefList 是一个动态数组。

我想将 XRefList 保存到 FileStream。如何做到这一点并包含所有 IndiName 和 ReportIndiName 字符串,以便以后从该 FileStream 加载时它们都可以再次检索?

【问题讨论】:

标签: delphi filestream dynamic-arrays


【解决方案1】:
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;

【讨论】:

  • 您可以在 LoadString 中使用 pointer(Result)^ 而不是 Result[1],在 SaveString 中使用 pointer(S)^ 而不是 S[1],因为它会保存对 UniqueString() 的调用.如果在所有情况下使用 result := '' 编码 LoadString 也可能会更快一些,然后如果 N>0 则使用 SetLength(Result,N) :因此不会有内存重新分配(移动缓慢),但字符串最终确定新分配(更快)。
  • 使用 TReader/TWriter 来简化标准数据类型的写入。而不是 Stream.WriteBuffer(N, SizeOf(Integer));您只需编写 Write.WriteInger(N) 和 N := Reader.ReadInteger;。它们还支持字符串和变体,并且代码更具可读性。您只是复制了 Delphi 已有的代码。
  • @ldsandon:TReader/TWriter 实现取决于 Delphi 版本,可能会改变。不希望依赖 TReader/TWriter 方法来实现自己的数据序列化。
  • OP 记录结构也会发生变化——您的代码也取决于 Delphi 的版本。如果该文件应在使用不同版本的 Delphi 编译的应用程序中使用,则应添加包含版本信息的标头以允许读取应用程序使用正确的读取功能。
【解决方案2】:

使用:http://code.google.com/p/kblib/

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

  TXRefList = array of IndiReportIndi;

var
  XRefList: TXRefList;

将整个 XRefList 保存到流使用:

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

要加载它:

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

【讨论】:

  • 看起来很不错。感谢您指出。
【解决方案3】:
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;  

要读取这些数据,请使用 TReader 和 ReadInteger/ReadString。

【讨论】:

  • 感谢 ldsandon。漂亮,干净,简单。 +1。
【解决方案4】:

简单的 TFileStreamEx 保存变量

http://forum.chertenok.ru/viewtopic.php?t=4642

从 2005 年开始与他们合作,没有任何问题...

【讨论】:

  • 不知道 EX 功能。我得调查一下。
【解决方案5】:

只是为了回答准确:

考虑查看TDynArray 包装器,它能够将任何记录序列化为二进制,也可以与动态数组进行交互。

有很多类似TList 的方法,包括新方法(如散列或二分查找)。

针对速度和磁盘使用进行了优化,适用于 Delphi 5 到 XE2 - 和开源。

另见How to store dynamic arrays in a TList?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-26
    • 2010-11-02
    • 1970-01-01
    • 1970-01-01
    • 2014-01-12
    • 1970-01-01
    相关资源
    最近更新 更多