例如,我有几种要从文件读取的记录类型
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;
编译器在E2571 Type parameter 'T' doesn't have class or interface constraint
处给我错误rd := stream.Read(T, sizeof(T));
。是否可以将该通用记录作为参数传递给TFileStream.Read函数?
答案 0 :(得分: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;
提供通用流类比提供诸如TFileStream
之类的特定流类更为灵活。这使您可以将这种方法用于不同的流实现。
您引发的查找异常没有任何作用,因为可以在文件末尾查找。在后续的读取或写入操作中会出现任何错误。
另一个异常很好,但是使用ReadBuffer
可能更简单,并且在无法读取请求的数据量的情况下,让流类引发一个异常。
答案 1 :(得分: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;
或者:
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;