如何将通用记录作为参数传递给TFileStream.Read函数?

use*_*150 3 delphi

例如,我有几种要从​​文件读取的记录类型

  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;
Run Code Online (Sandbox Code Playgroud)

我想使用通用功能从文件中读取

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;
Run Code Online (Sandbox Code Playgroud)

编译器给我错误E2571 Type parameter 'T' doesn't have class or interface constraintrd := stream.Read(T, sizeof(T));。是否可以将该通用记录作为参数传递给TFileStream.Read函数?

Vil*_*nde 8

您正在尝试直接读取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;
Run Code Online (Sandbox Code Playgroud)

与其提供像一样的特定流类TFileStream,不如提供一个通用流类更加灵活。这使您可以将此方法与不同的流实现一起使用。

引发的查找异常没有任何作用,因为可以在文件末尾进行查找。在后续的读取或写入操作中会出现任何错误。

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


Rem*_*eau 7

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

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

implementation

class procedure TReaderHelper.ReadToStruct<T>(stream: TFileStream; offset: Int64; out rec: T);
var
  rd: integer;
begin
  stream.Position := offset;
  if stream.Position <> offset then
    raise Exception.Create('Seek error');
  rd := stream.Read(rec, sizeof(T));
  if rd <> sizeof(T) then
    raise Exception.Create('Read ' + IntToStr(rd) + ' instead of ' + IntToStr(sizeof(T)));
end;
Run Code Online (Sandbox Code Playgroud)

或者:

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

implementation

class function TReaderHelper.ReadToStruct<T>(stream: TFileStream; offset: Int64): T;
var
  rd: integer;
begin
  stream.Position := offset;
  if stream.Position <> offset then
    raise Exception.Create('Seek error');
  rd := stream.Read(Result, sizeof(T));
  if rd <> sizeof(T) then
    raise Exception.Create('Read ' + IntToStr(rd) + ' instead of ' + IntToStr(sizeof(T)));
end;
Run Code Online (Sandbox Code Playgroud)