delphi - 如果 Windows/Delphi/IDE 暗示小端顺序,我如何从大端二进制文件中读取整数?
问题描述
我很困扰。我需要读取二进制文件(Applied Biotechnology 的 .fsa 扩展名,又名 ABIF、FASTA 文件),但在读取有符号整数时遇到了问题。我正在根据本 手册https://drive.google.com/file/d/1zL-r6eoTzFIeYDwH5L8nux2lIlsRx3CK/view?usp=sharing //drive.google.com/file/d/1rrL01B_gzgBw28knvFit6hUIA5jcCDry/view?usp=sharing
我知道它应该是 2688(根据手册,它是一个 32 位的有符号整数),即 00000000 00000000 00001010 10000000 的二进制形式。实际上,当我将这 32 位作为 4 字节数组读取时,我得到 [0, 0, 10, -128],这与二进制形式完全相同。
但是,如果我将其读取为整数,则结果为 16809994,即 00000001 00000000 10000000 00001010 位。
正如我从多个论坛了解的那样,他们使用 Swap 和 htonl 函数将整数从小端顺序转换为大端顺序。他们还建议对 32 位整数使用 BSWAP EAX 指令。但是在这种情况下,它们以一种错误的方式工作,具体来说:交换,应用于 16809994,返回 16779904 或 00000001 00000000 00001010 10000000,BSWAP 指令将 16809994 转换为 176160769,即 0000100000000000000
正如我们所看到的,内置函数做的事情与我需要的不同。交换可能会返回正确的结果,但由于某种原因,将这些位作为整数读取会更改最左边的字节。那么,出了什么问题,我该怎么办?
更新。1 为了存储标题数据,我使用以下记录:
type
TFasMainHeader = record
fFrmt : array[1..4] of ansiChar;
fVersion : Word;
fDir : array[1..4] of ansiChar;
fNumber : array[1..4] of Byte; //
fElType : Word;
fElSize : Word;
fNumEls : array[1..4] of Byte; //
fDataSize : Integer;
fDataOffset : Integer;
fDO : word;
fDataHandle : array[1..98] of Byte;
end;
然后单击按钮,我执行以下操作:
aFileStream.Read(fas_main_header, SizeOf(TFasMainHeader));
with fas_main_header do begin
if fFrmt <> 'ABIF' then raise Exception.Create('Not an ABIF file!');
fVersion := Swap(fVersion);
fElType := Swap(fElType);
fElSize := Swap(fElSize);
...
接下来我需要以正确的方式交换Int32变量,但是此时fDataSize例如是16809994。调试时详细查看记录的状态:
这对我来说没有意义,因为 fDataSize 值的二进制表示中不应该有一位(它也会破坏 BSWAP 结果)。
解决方案
该问题与字节顺序无关,而是与 Delphi记录有关。
你有
type
TFasMainHeader = record
fFrmt : array[1..4] of ansiChar;
fVersion : Word;
fDir : array[1..4] of ansiChar;
fNumber : array[1..4] of Byte; //
fElType : Word;
fElSize : Word;
fNumEls : array[1..4] of Byte; //
fDataSize : Integer;
fDataOffset : Integer;
fDO : word;
fDataHandle : array[1..98] of Byte;
end;
并且您希望此记录覆盖文件中的字节,并带有fDataSize
"on top of" 00 00 0A 80
。
但是 Delphi 编译器会在记录的字段之间添加填充以使它们正确对齐。因此,您fDataSize
将不会处于正确的偏移量。
要解决此问题,请使用packed
关键字:
type
TFasMainHeader = packed record
fFrmt : array[1..4] of ansiChar;
fVersion : Word;
fDir : array[1..4] of ansiChar;
fNumber : array[1..4] of Byte; //
fElType : Word;
fElSize : Word;
fNumEls : array[1..4] of Byte; //
fDataSize : Integer;
fDataOffset : Integer;
fDO : word;
fDataHandle : array[1..98] of Byte;
end;
然后这些字段将位于预期的位置。
然后——当然——你可以使用任何你喜欢的方法来交换字节顺序。
最好是BSWAP
指令。
推荐阅读
- javascript - React Native - 动态添加元素后滚动到元素
- kubernetes - 如何使用 kubectl 安装 kubernetes / ingress-nginx?(不是掌舵)
- javascript - 我不明白为什么我会收到此错误
- botframework - 如何知道用户是否在 Teams 中阻止了机器人
- android - 删除应用后,SharedPreferences 会自动从设备中删除吗?
- rx-java - 如何将 RX.Observable 转换为 IO.reactivex.Observable
- javascript - 如何将变量从 Node JS 传递到前端 JS
- amazon-web-services - Aws Lambda 写入 Firebase 存储
- go - go.mod 替换指令被忽略
- python - instaloader模块的download_story item()方法中的target参数