我试图写一些代码来将对象的动态数组读/写到文件中。这些对象表示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;
结束;
结束。