2

我正在尝试编写一些代码,这些代码会将动态对象数组读/写到文件中。对象表示 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;
4

1 回答 1

1

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

关于这一点的几点说明:

  • 有很多不同的方法可以解决这个问题。听从 David Heffernan 的建议,对序列化进行一些搜索。我在我的一个应用程序中使用了以下方法,但其他方法包括使用 RTTI/Persistent 对象来迭代对象的已发布属性。有些库会为您迭代对象并完成所有工作。

  • 您需要将动态对象的大小实际写入字符串。这包括数组和字符串之类的东西。

  • 在我的示例中,每个对象都知道如何将自己读写到流中。

  • 我对对象的固定长度部分使用结构。这使我无需单独编写每个数据元素。

  • 字符串需要自己编写以包含它们的大小(您可以使用像 Delphi 短字符串这样的固定长度缓冲区,但写出常规字符串并没有太多工作。您需要确定您想要的字符串数据的格式类型写在。我为我的应用程序选择了 UTF8。

  • 对于您的其他数组,您可以在写出第一个数组后写入它们的数据(包括长度)。有时会有一个标题部分,其中包括顶部所有动态部分的长度,其他人将在结构开始之前写入长度写入。关键部分是始终以相同的顺序编写内容并包含在可以重新读取的地方。

  • 下面的文件结构中没有错误检查或验证。如果读取和写入之间有任何不同,它就会爆炸——可能是流读取错误。

  • 对结构的任何更改都将导致无法正确读取旧文件。有多种方法可以对文件进行版本控制,以确保您仍然可以阅读旧格式。这里不包括。

  • 在您的应用程序中,您可以将 TFileStream 传递给 read 和 write 函数。我喜欢只用 TStream 编写实际的读/写函数。然后对象不关心数据来自哪里。它可能是文件,也可能已经在内存中。

  • 如果您将以下单元放入控制台应用程序中,您应该能够添加对 Main 的调用并逐步执行示例。

    
    单元核心结构;

    界面

    使用类、类型;

    类型

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

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

          过程 SetNestedStruc(AValue: TCoreStruc);
        上市
          核心类型:字符串;
          名称:字符串;


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

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

          属性LowerPointer:整数读取FCoreData.LowerPointer写入FCoreData.LowerPointer;
          属性 HigherPointer:整数读取 FCoreData.HigherPointer 写入 FCoreData.HigherPointer;
          属性 Line:整数 读取 FCoreData.Line 写入 FCoreData.Line;
          属性 Word:整数 读取 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(指针(Buffer8)^, n);

      结果:=字符串(缓冲区8);

    结尾;


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

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

      Stream.WriteBuffer(指针(Buffer8)^, n);

    结尾;


    程序 Main();
    变量
      结构体:TCoreStruc 数组;

      数组大小:整数;
      数据流:TMemoryStream;

      ArraySize_A:整数;
      Structs_A:TCoreStruc 数组;
      i:整数;
    开始
      // 创建并写入一些数据
      设置长度(结构,3);
      结构[0] := TCoreStruc.Create();
      结构[0].HigherPointer := 1;
      Structs[0].Name := '测试';

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

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

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


      数据流 := TMemoryStream.Create();

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

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


      // 将数据读入一组新的对象
      数据流.位置:= 0;

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

      对于 i := 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(名称,流);
      WriteUtf8StringToStream(CoreType, Stream);

      如果 FCoreData.HasNested = true 那么
      开始
        FNestedStruc.WriteToStream(流)
      结尾;

    结尾;

    过程 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;

    结尾;



    结尾。
于 2013-06-18T15:37:40.780 回答