Delphi 如何将泛型记录作为参数传递给TFileStream.Read函数?

Delphi 如何将泛型记录作为参数传递给TFileStream.Read函数?,delphi,Delphi,例如,我有几种记录类型可以从文件中读取 PDescriptorBlockHeader = ^TDescriptorBlockHeader; TDescriptorBlockHeader = packed record BlockType: UInt32; BlockAttributes: UInt32; // +4 OffsetToFirstEvent: UInt16; // +8 OsId: byte; // +10 OsVersion: by

例如,我有几种记录类型可以从文件中读取

  PDescriptorBlockHeader = ^TDescriptorBlockHeader;
  TDescriptorBlockHeader = packed record

    BlockType: UInt32;
    BlockAttributes: UInt32; // +4
    OffsetToFirstEvent: UInt16; // +8
    OsId: byte; // +10
    OsVersion: byte;
    DisplayableSize: UInt64;  // +12
    FormatLogicalAddress: UInt64; // +20
    SessionId: UInt64; // +28
    ControlBlockID: UInt32; // +36
    StringStorage: MTF_TAPE_ADDRESS; // +40
    OsSpecificData: MTF_TAPE_ADDRESS; // +44
    StringType: byte; // +48
    Reserved: byte; // +49
    HeaderChecksum: UInt16; //+50
  end;
我想使用公共函数来读取文件

type
  TReaderHelper = class
    class procedure ReadToStruct<T:record>(stream: TFileStream; offset: Int64);
  end;

implementation

class procedure TReaderHelper.ReadToStruct<T>(stream: TFileStream; offset: Int64);
var
  rd: integer;
begin
  stream.Position := offset;
  if stream.Position <> offset then
    raise Exception.Create('Seek error');
  rd := stream.Read(T, sizeof(T));
  if rd <> sizeof(T) then
    raise Exception.Create('Read ' + IntToStr(rd) + ' instead of ' + IntToStr(sizeof(T)));
end;
类型
踏板帮助器=类
类过程ReadToStruct(流:TFileStream;偏移量:Int64);
结束;
实施
类过程TReaderHelper.ReadToStruct(流:TFileStream;偏移量:Int64);
变量
rd:整数;
开始
流位置:=偏移量;
如果流。位置偏移,则
引发异常。创建('Seek error');
rd:=stream.Read(T,sizeof(T));
如果rd sizeof(T)那么
引发异常。创建('Read'+IntToStr(rd)+'而不是'+IntToStr(sizeof(T)));
结束;

编译器在
rd:=stream.Read(T,sizeof(T))处给我错误
E2571类型参数“T”没有类或接口约束。是否可以将该通用记录作为参数传递给TFileStream.Read函数?

您正试图直接读取到
T
,这是类型。您需要提供一个要读入的变量类型

type
  TReaderHelper = class
    class procedure ReadToStruct<T: record>(stream: TStream; offset: Int64; out Data: T);
  end;

class procedure TReaderHelper.ReadToStruct<T>(stream: TStream; offset: Int64; out Data: T);
begin
  stream.Position := offset;
  stream.ReadBuffer(Data, sizeof(T));
end;
类型
踏板帮助器=类
类过程ReadToStruct(流:TStream;偏移量:Int64;输出数据:T);
结束;
类过程TReaderHelper.ReadToStruct(流:TStream;偏移量:Int64;输出数据:T);
开始
流位置:=偏移量;
ReadBuffer(数据,sizeof(T));
结束;
与其提供像
TFileStream
这样的特定流类,不如提供一个通用流类。这允许您将此方法用于不同的流实现

您提出的seek异常没有任何作用,因为可以在文件结尾之外进行查找。后续读或写操作中出现任何错误


另一个异常很好,但使用
ReadBuffer
并让流类在请求的数据量无法读取时引发异常可能更简单。

T
表示类型,而不是变量。您需要将变量传递给
Read()
。在代码中添加一个输出变量并读入其中,例如:

类型
踏板帮助器=类
类过程ReadToStruct(流:TFileStream;偏移量:Int64:out rec:T);
结束;
实施
类过程TReaderHelper.ReadToStruct(流:TFileStream;偏移量:Int64;输出记录:T);
变量
rd:整数;
开始
流位置:=偏移量;
如果流。位置偏移,则
引发异常。创建('Seek error');
rd:=stream.Read(rec,sizeof(T));
如果rd sizeof(T)那么
引发异常。创建('Read'+IntToStr(rd)+'而不是'+IntToStr(sizeof(T)));
结束;
或者:

类型
踏板帮助器=类
类函数ReadToStruct(流:TFileStream;偏移量:Int64):T;
结束;
实施
类函数TReaderHelper.ReadToStruct(流:TFileStream;偏移量:Int64):T;
变量
rd:整数;
开始
流位置:=偏移量;
如果流。位置偏移,则
引发异常。创建('Seek error');
rd:=stream.Read(结果,sizeof(T));
如果rd sizeof(T)那么
引发异常。创建('Read'+IntToStr(rd)+'而不是'+IntToStr(sizeof(T)));
结束;