delphi - 将对象的动态数组读取/写入文件-Delphi

标签 delphi

我试图写一些代码来将对象的动态数组读/写到文件中。这些对象表示Java源代码的结构。我需要能够扫描整个源代码并收集有关字段,方法和类的信息。我有一个算法可以做到这一点,结果保存在TFieldStruc,TMethodStruc和TClassStruc的结构中,它们是TCoreStruc的所有后代(TObject的后代)。 Java源代码需要花费几分钟的时间进行扫描并生成虚拟结构。因此,我的应用程序扫描了所有源代码一次,并将其保存为更易于访问的格式,该格式可在IDE启动时加载。

有没有一种方法(除了将对象导出为“字符串”,然后在加载时再次重新创建它们),将TFieldStruc,TMethodStruc和TClassStruc的整个三个数组流式传输到文件中,以便以后可以读取?

我曾尝试读写“ TFieldStruc ..的文件”和TFileStream来将对象保存到文件中并读回,但是在两种情况下,我在调试器中都得到“不可访问的值”,然后出现“访问冲突”再次访问该对象时出错。如果有人对如何解决此问题有想法,将不胜感激。如果其任何字段/方法可能引起问题,则下面是TCodeStruc的代码:

type
  TCoreStruc = class(TObject)
    public
      LowerPointer : integer;
      HigherPointer : integer;
      Line : integer;
      Word : integer;
      Char : integer;
      CoreType : ansistring;
      IsPublic : boolean;
      IsPrivate : boolean;
      IsStatic : boolean;
      IsFinal : boolean;
      Name : ansistring;
      NestedStruc : TCoreStruc;
      constructor Create(Name, CoreType : ansistring; NestedStruc : TCoreStruc; IsPublic, IsPrivate, IsStatic, IsFinal : boolean);
      procedure UpdateValues(NestedStruc : TCoreStruc; IsPublic, IsPrivate, IsStatic, IsFinal : boolean);
      procedure SetPosition(Line, Word, Char : integer);
  end;

最佳答案

这是使用您的结构的示例。

关于此的一些注意事项:


有很多不同的方法可以解决此问题。采纳David Heffernan的建议,并进行一些搜索以进行序列化。我在一个应用程序中使用了以下方法,但其他方法包括使用RTTI / Persistent对象迭代对象的已发布属性。有一些库会为您迭代对象并完成所有工作。
您实际上需要在字符串中写出动态对象的大小。包括数组和字符串之类的东西。
在我的示例中,每个对象都知道如何读写流。
我对对象的固定长度部分使用结构。这使我免于需要单独编写每个数据元素的麻烦。
字符串需要自己编写以包括其大小(您可以使用固定长度的缓冲区,例如Delphi短字符串,但是写出常规字符串的工作量并不大。您需要确定所需的字符串数据格式类型)写的。我为我的应用程序选择了UTF8。
对于其他阵列,您可以在第一个阵列写完后写入其数据(包括长度)。有时会有一个标头部分,其顶部包括所有动态部分的长度,其他部分将在结构开始之前写入长度。关键部分是始终以相同的顺序编写内容,并且将其包含在可以重新读取的位置。
下面的文件结构中没有错误检查或验证。如果读取和写入之间有任何不同,它将崩溃—可能是流读取错误。
结构的任何更改都将导致旧文件无法正确读取。有多种方法可以对文件进行版本控制,以确保您仍可以阅读旧格式。不包括在这里。
在您的应用程序中,您可以将TFileStream传递给读写功能。我喜欢仅使用TStream编写实际的读/写功能。然后,该对象将不在乎数据来自何处。它可以是文件,也可以已经在内存中。
如果将以下单元放到控制台应用程序中,则应该可以添加对Main的调用并逐步执行该示例。





单位CoreStruct;

接口

使用类,类型;

类型

TCoreStructData =打包记录
LowerPointer:整数;
HigherPointer:整数;
行:整数;
字:整数;
Char:整数;
IsPublic:布尔值;
IsPrivate:布尔值;
IsStatic:布尔值;
IsFinal:布尔值;
HasNested:布尔值;
结束;

TCoreStruc =类(TObject)
私人的
FCoreData:TCoreStructData;
FNestedStruc:TCoreStruc;

过程SetNestedStruc(AValue:TCoreStruc);
上市
CoreType:字符串;
名称:字符串;


构造函数Create();超载;
过程WriteToStream(Stream:TStream);
过程ReadFromStream(Stream:TStream);

//构造函数Create(Name,CoreType:ansistring; NestedStruc:TCoreStruc; IsPublic,IsPrivate,IsStatic,IsFinal:布尔值);超载;
//过程UpdateValues(NestedStruc:TCoreStruc; IsPublic,IsPrivate,IsStatic,IsFinal:布尔值);
//过程SetPosition(Line,Word,Char:integer);

属性LowerPointer:读取FCoreData.LowerPointer的整数,写入FCoreData.LowerPointer;
属性HigherPointer:读取FCoreData.HigherPointer的整数,写入FCoreData.HigherPointer;
属性Line:读取FCoreData.Line的整数,写入FCoreData.Line;
属性字:整数读取FCoreData.Word写FCoreData.Word;
属性Char:读取FCoreData.Char的整数,写入FCoreData.Char;

属性NestedStruc:TCoreStruc读取FNestedStruc写入SetNestedStruc;
结束;

过程Main();

实施


函数ReadUTF8StringFromStream(const Stream:TStream):String;
变种
n:整数;
Buffer8:Utf8String;
开始
结果:='';

Stream.ReadBuffer(n,SizeOf(n));

如果n = 0则
出口;

SetLength(Buffer8,n);
Stream.ReadBuffer(Pointer(Buffer8)^,n);

结果:= String(Buffer8);

结束;


过程WriteUtf8StringToStream(const Data:String; Stream:TStream);
变种
Buffer8:Utf8String;
n:整数;
开始
//编写字符串时,我们需要确保
//将字符串写出到流中。首先,所以
//读者知道缓冲区有多长时间。
//
//您可以根据不同的格式写入文件
//需求。我喜欢在写入文件时使用UTF8,但确实如此
//将其变回本机时需要额外的缓冲区副本
// Delphi unicode字符串。
Buffer8:= Utf8String(Data);
n:=长度(Buffer8);

Stream.WriteBuffer(n,SizeOf(n));

Stream.WriteBuffer(Pointer(Buffer8)^,n);

结束;


过程Main();
变种
结构:TCoreStruc数组;

ArraySize:整数;
DataStream:TMemoryStream;

ArraySize_A:整数;
Structs_A:TCoreStruc数组;
i:整数;
开始
//创建和写入一些数据
SetLength(Structs,3);
Structs [0]:= TCoreStruc.Create();
结构[0] .HigherPointer:= 1;
结构[0]。名称:='正在测试';

Structs [0] .NestedStruc:= TCoreStruc.Create();
Structs [0] .NestedStruc.HigherPointer:= 100;

Structs [1]:= TCoreStruc.Create();
结构[1] .HigherPointer:= 2;

Structs [2]:= TCoreStruc.Create();
结构[2] .HigherPointer:= 3;


DataStream:= TMemoryStream.Create();

//我们需要从要写的计数开始
//读者知道要循环多少次。
ArraySize:=长度(结构);
DataStream.WriteBuffer(ArraySize,SizeOf(integer));

对于我:= 0到ArraySize-1
开始
结构[i] .WriteToStream(DataStream);
结束;


//将数据读入一组新的对象
DataStream.Position:= 0;

DataStream.ReadBuffer(ArraySize_A,SizeOf(integer));
SetLength(Structs_A,ArraySize_A);

对于我:= 0到ArraySize_A-1
开始
Structs_A [i]:= TCoreStruc.Create();
Structs_A [i] .ReadFromStream(DataStream);
结束;

结束;

{TCoreStruc}

构造函数TCoreStruc.Create;
开始
Self.LowerPointer:= 0;
Self.HigherPointer:= 0;
Self.Line:= 0;
Self.Word:= 0;
Self.Char:= 0;

Self.NestedStruc:= nil;

结束;

过程TCoreStruc.WriteToStream(Stream:TStream);
开始
Stream.WriteBuffer(FCoreData,SizeOf(TCoreStructData));
WriteUtf8StringToStream(Name,Stream);
WriteUtf8StringToStream(CoreType,Stream);

如果FCoreData.HasNested = true,则
开始
FNestedStruc.WriteToStream(Stream)
结束;

结束;

过程TCoreStruc.ReadFromStream(Stream:TStream);
开始

Stream.ReadBuffer(FCoreData,SizeOf(TCoreStructData));
名称:= ReadUtf8StringFromStream(Stream);
名称:= ReadUtf8StringFromStream(Stream);

如果FCoreData.HasNested = true,则
开始
FNestedStruc:= TCoreStruc.Create();
FNestedStruc.ReadFromStream(Stream);
结束;

结束;

过程TCoreStruc.SetNestedStruc(AValue:TCoreStruc);
开始
FNestedStruc:= AValue;

如果AValue = nil,则
FCoreData.HasNested:=否
其他
FCoreData.HasNested:= true;

结束;



结束。

关于delphi - 将对象的动态数组读取/写入文件-Delphi,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17153172/

相关文章:

Delphi 2007 和更新的 Indy 10

delphi - 如何通过 OleAutomation 删除或更改附加模板

delphi - 类帮助器语法中 `ancestor list` 的用途是什么?它记录在哪里?有使用示例吗?

delphi - 调用从接口(interface)和另一个祖先继承的类的方法

delphi - 如何在TStringGrid中显示行号?

delphi - "Library path"应该指向包的源文件吗?

c++ - 使用 thiscall 约定调用 C++ 成员函数

android - 不使用实时绑定(bind)以编程方式构建 TListView

Delphi 组件中的 PNG 图像集合

Delphi - 如何向 TDataModule 发送 Windows 消息?