Bin 数据在 AIX 中的读取方式与 Linux 不同

Bin data read differently in AIX vs Linux

我有一个包含斜率和截距的 .bin 文件。我正在使用 Fortran 来读取这些值,但我在机器 运行 AIX 和 Linux 上得到了不同的值。我相信 Linux 数据是准确的。这与堆栈大小或字节序有关吗?

例如,AIX 最大值为:0.3401589687E+39 而Linux最大值为:6.031288

program read_bin_files

REAL :: slope(2500,1250)
INTEGER :: recl=2500*1250*4

OPEN(UNIT=8, FILE='MODIS_AVHRR_years_slope.bin', ACTION='READ', ACCESS='direct', FORM='unformatted', RECL=recl, IOSTAT=iostat)

READ(unit=8, REC = 1, IOSTAT = iostat) slope
print *, "Max slope value is:", maxval(slope)

CLOSE(8)

end

AIX 运行s(这些天)在 POWER CPUs 上,通常是 big-endian,而 Linux在 x86es 上通常是 运行,这是 little-endian。所以你怀疑字节顺序可能是一个问题是正确的。您报告 运行ning this program

的结果
program read_bin_files

    INTEGER*4 :: slope(2500,1250)
    INTEGER   :: recl=2500*1250*4

    OPEN(UNIT=8, FILE='MODIS_AVHRR_years_slope.bin', ACTION='READ', &
         ACCESS='direct', FORM='unformatted', RECL=recl)

    READ(unit=8, REC = 1) slope

    DO i = 1, 10
        WRITE(*, '(Z8.8)') slope(1, i)
    END DO

    CLOSE(8)

end

如下。 ("AIX" 和 "Linux" 在 headers 列中用引号括起来,因为这里重要的是 CPU,而不是操作系统。 )

  "Linux"   |   "AIX"
------------+------------
3E C2 61 8F | 8F 61 C2 3E
3E F5 64 52 | 52 64 F5 3E
BC F3 E0 7E | 7E E0 F3 BC
BF B9 71 0D | 0D 71 B9 BF
3E F5 B9 73 | 73 B9 F5 3E
3F 29 3C 2F | 2F 3C 29 3F
3E DC C2 09 | 09 C2 DC 3E
3F 66 86 89 | 89 86 66 3F
3E 5B 91 A9 | A9 91 5B 3E
3F 67 73 25 | 25 73 67 3F

在每一行中,right-hand 一半是 left-hand 一半的镜像。这表明问题 字节顺序。我们仍然不知道哪种字节顺序是正确的。这个问题的答案几乎肯定是 "the byte order used by the CPU that ran the program that generated the file."

如果您使用的是 GNU Fortran,the CONVERT specifier to OPEN 应该可以解决问题,前提是您可以弄清楚应该以哪种方式解释数据。但是,我 认为 这是一个扩展。在一般情况下,我对 FORTRAN 的了解还不够多,无法告诉您该怎么做。

如果您可以控制生成这些数据文件的过程,则可以通过将双方切换为 self-describing 数据格式来避免将来出现整个问题,例如 HDF.

您的 AIX 机器可能是 big-endian RISC,您的 Linux 可能是 PC 或其他 Intel 平台。只需转换字节顺序即可。

我将这些过程用于 4 字节和 8 字节变量(在模块中使用 iso_fortran_env):

elemental function SwapB32(x) result(res)
  real(real32) :: res
  real(real32),intent(in) :: x
  character(4) :: bytes
  integer(int32) :: t
  real(real32) :: rbytes, rt
  equivalence (rbytes, bytes)
  equivalence (t, rt)

  rbytes = x
  t = ichar(bytes(4:4),int32)    
  t = ior( ishftc(ichar(bytes(3:3),int32),8),  t )
  t = ior( ishftc(ichar(bytes(2:2),int32),16), t )
  t = ior( ishftc(ichar(bytes(1:1),int32),24), t )
  res = rt
end function

elemental function SwapB64(x) result(res)
  real(real64) :: res
  real(real64),intent(in) :: x
  character(8) :: bytes
  integer(int64) :: t
  real(real64) :: rbytes, rt
  equivalence (rbytes, bytes)
  equivalence (t, rt)

  rbytes = x
  t = ichar(bytes(8:8),int64)
  t = ior( ishftc(ichar(bytes(7:7),int64),8),  t )
  t = ior( ishftc(ichar(bytes(6:6),int64),16), t )
  t = ior( ishftc(ichar(bytes(5:5),int64),24), t )
  t = ior( ishftc(ichar(bytes(4:4),int64),32), t )
  t = ior( ishftc(ichar(bytes(3:3),int64),40), t )
  t = ior( ishftc(ichar(bytes(2:2),int64),48), t )
  t = ior( ishftc(ichar(bytes(1:1),int64),56), t )
  res = rt
end function

用法:

SLOPE = SwapB32(SLOPE)

还有其他方法。一些编译器支持非标准 OPEN(...,CONVERT='big_endian',...,一些编译器有命令行选项,如 -fconvert=big-endian.

基本函数 SwapB64 很优雅,很适合解决这些问题。 要么 使用 big_endian、little endian 等尝试这些。 (我个人会两者都做)

!OPEN(UNIT=8, FILE='MODIS_AVHRR_years_slope.bin', ACTION='READ', ACCESS='direct', FORM='unformatted', RECL=recl, IOSTAT=iostat)

OPEN(UNIT=8, FILE='MODIS_AVHRR_years_slope.bin', CONVERT='big_endian', ACTION='READ', ACCESS='direct', FORM='unformatted', RECL=recl, IOSTAT=iostat)