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

时间:2016-07-25 19:38:02

标签: linux fortran binaryfiles aix endianness

我有一个包含斜率和截距的.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

3 个答案:

答案 0 :(得分:1)

AIX运行(现在)在POWER CPU上运行,这些通常是 big-endian,而Linux 通常在x86es上运行,它们是little-endian。所以你怀疑字节序可能是一个问题是正确的。您报告运行程序

的结果
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"和#34; Linux"在列标题中都有引号,因为它是 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

在每一行中,右半部分是左半部分的镜像。这表明问题字节序。我们还不知道哪个字节顺序正确。该问题的答案几乎肯定是"运行生成文件的程序的CPU使用的字节顺序。"

如果您使用的是GNU Fortran,the CONVERT specifier to OPEN应该可以解决问题,前提是您可以找出应该解释数据的方式。但是,我认为是一个扩展。在一般情况下,我不太了解FORTRAN告诉你该怎么做。

如果您可以控制生成这些数据文件的过程,则可以通过将双方切换为自我描述的数据格式(例如HDF)来避免整个问题。

答案 1 :(得分:1)

您的AIX机器可能是大端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等命令行选项。

答案 2 :(得分:0)

元素函数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)