阅读/写动态数组的对象到一个文件- Delphi

vhmi4jdf  于 2022-11-04  发布在  其他
关注(0)|答案(1)|浏览(113)

我正在尝试写一些代码,它将读/写一个动态数组的对象到一个文件。对象代表java源代码的结构。我需要能够扫描整个源代码,并收集有关字段,方法和类的信息。我有一个算法,它可以做到这一点,结果保存在一个结构的TFieldStruc,TMethodStruc和TClassStruc。TCoreStruc(TObject的后代)的所有后代。Java源代码需要几分钟的时间来扫描并生成虚拟结构。因此,我的应用程序一次扫描所有源代码,并将其保存为更易于访问的格式,当IDE启动时加载该格式。
是否有一种方法(除了将对象“导出到字符串”,然后在加载时重新创建它们之外)可以将TFieldStruc、TMethodStruc和TClassStruc的整个三个数组流到一个文件中,以便以后可以读取它们?
我尝试过阅读'FileofTFieldStruc..'和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;
1u4esq0p

1u4esq0p1#

下面是一个使用您的结构的示例。
关于这一点,请注意以下几点:

  • 有很多不同的方法来实现这个。接受大卫Heffernan的建议,做一些序列化的搜索。我在我的一个应用程序中使用了下面的方法,但其他方法包括使用RTTI/Persistent对象来迭代对象的已发布属性。有一些库可以为你迭代对象,并完成所有的工作。
  • 你需要把动态对象的大小写进字符串,包括数组和字符串.
  • 在我的示例中,每个对象都知道如何将其自身读取和写入流。
  • 我使用一个结构体来表示对象的固定长度部分,这样就不必单独写每个数据元素。
  • 字符串需要自己编写,以包括它们的大小(你可以使用一个固定长度的缓冲区,如 Delphi 短字符串,但写出一个常规的字符串并不需要太多的工作。你需要决定你想要用什么类型的格式写入字符串数据。我为我的应用程序选择了UTF8。
  • 对于其他的数组,你可以在第一个数组写出来之后再写它们的数据(包括长度)。有时候会有一个头部分,在顶部包含所有动态部分的长度,其他的会在结构开始之前写长度。关键的部分是总是以相同的顺序写东西,并在某个地方包含它,它可以重新读取有多少。
  • 在下面的文件结构中没有错误检查或验证。如果读和写之间有任何不同,它会爆炸-可能是流读错误。
  • 对结构的任何更改都将导致旧文件无法正确读取。有多种方法可以对文件进行版本控制,以确保您仍然可以读取旧格式。此处不包括。
  • 在你的应用程序中,你可以将一个TFileStream传递给读写函数。我喜欢用一个TStream来编写实际的读写函数。这样对象就不会关心数据来自哪里。它可能是文件,也可能已经在内存中了。
  • 如果您将以下单元拖放到控制台应用程序中,您应该能够添加对Main的调用并逐步执行该示例。
unit CoreStruct;

interface

uses Classes, Types;

type

  TCoreStructData = packed record
    LowerPointer : integer;
    HigherPointer : integer;
    Line : integer;
    Word : integer;
    Char : integer;
    IsPublic : boolean;
    IsPrivate : boolean;
    IsStatic : boolean;
    IsFinal : boolean;
    HasNested: boolean;
  end;

  TCoreStruc = class(TObject)
    private
      FCoreData: TCoreStructData;
      FNestedStruc : TCoreStruc;

      procedure SetNestedStruc(AValue: TCoreStruc);
    public
      CoreType : String;
      Name : String;

      constructor Create(); overload;
      procedure WriteToStream(Stream: TStream);
      procedure ReadFromStream(Stream: TStream);

      //constructor Create(Name, CoreType : ansistring; NestedStruc : TCoreStruc; IsPublic, IsPrivate, IsStatic, IsFinal : boolean); overload;
      //procedure UpdateValues(NestedStruc : TCoreStruc; IsPublic, IsPrivate, IsStatic, IsFinal : boolean);
      //procedure SetPosition(Line, Word, Char : integer);

      property LowerPointer: integer read FCoreData.LowerPointer write FCoreData.LowerPointer;
      property HigherPointer: integer read FCoreData.HigherPointer write FCoreData.HigherPointer;
      property Line: integer read FCoreData.Line write FCoreData.Line;
      property Word: integer read FCoreData.Word write FCoreData.Word;
      property Char: integer read FCoreData.Char write FCoreData.Char;

      property NestedStruc: TCoreStruc read FNestedStruc write SetNestedStruc;
  end;

  procedure Main();

implementation

function ReadUTF8StringFromStream(const Stream: TStream): String;
var
  n: Integer;
  Buffer8: Utf8String;
begin
  Result := '';

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

  if n = 0 then
    Exit;

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

  Result := String(Buffer8);
end;

procedure WriteUtf8StringToStream(const Data: String; Stream: TStream);
var
  Buffer8: Utf8String;
  n: Integer;
begin
  // When writing strings we need to make sure the length of the
  // string is written out to the stream.  That goes first so the
  // reader knows how long the buffer is.
  //
  // You could you different formats to write to the file depending on
  // needs.  I like using UTF8 when writing out to file, but it does
  // require an extra buffer copy when turning it back into a native
  // Delphi unicode string.
  Buffer8 := Utf8String(Data);
  n := Length(Buffer8);

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

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

procedure Main();
var
  Structs: array of TCoreStruc;

  ArraySize: integer;
  DataStream: TMemoryStream;

  ArraySize_A: integer;
  Structs_A: array of TCoreStruc;
  i: integer;
begin
  // Create and write some data
  SetLength(Structs, 3);
  Structs[0] := TCoreStruc.Create();
  Structs[0].HigherPointer := 1;
  Structs[0].Name := 'Testing';

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

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

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

  DataStream := TMemoryStream.Create();

  // We need to start with the count we are writing out so
  // the reader knows how many times to loop.
  ArraySize := Length(Structs);
  DataStream.WriteBuffer(ArraySize, SizeOf(integer));

  for i := 0 to ArraySize - 1 do
  begin
    Structs[i].WriteToStream(DataStream);
  end;

  // Read the data into a new set of objects
  DataStream.Position := 0;

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

  for i := 0 to ArraySize_A - 1 do
  begin
    Structs_A[i] := TCoreStruc.Create();
    Structs_A[i].ReadFromStream(DataStream);
  end;
end;

{ TCoreStruc }

constructor TCoreStruc.Create;
begin
  Self.LowerPointer := 0;
  Self.HigherPointer := 0;
  Self.Line := 0;
  Self.Word := 0;
  Self.Char := 0;

  Self.NestedStruc := nil;
end;

procedure TCoreStruc.WriteToStream(Stream: TStream);
begin
  Stream.WriteBuffer(FCoreData, SizeOf(TCoreStructData));
  WriteUtf8StringToStream(Name, Stream);
  WriteUtf8StringToStream(CoreType, Stream);

  if FCoreData.HasNested = true then
  begin
    FNestedStruc.WriteToStream(Stream)
  end;
end;

procedure TCoreStruc.ReadFromStream(Stream: TStream);
begin

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

  if FCoreData.HasNested = true then
  begin
    FNestedStruc := TCoreStruc.Create();
    FNestedStruc.ReadFromStream(Stream);
  end;
end;

procedure TCoreStruc.SetNestedStruc(AValue: TCoreStruc);
begin
  FNestedStruc := AValue;

  if AValue = nil then
    FCoreData.HasNested := false
  else
    FCoreData.HasNested := true;
end;

end.

相关问题