从fortran写出二进制文件并在C中读取

时间:2013-11-15 17:05:48

标签: c++ c fortran

我正在尝试读取一个由fortran程序生成的二进制文件。我的输出中有一些奇怪的字符,可能是fortran和C都有不同的endianess吗?

3 个答案:

答案 0 :(得分:3)

你应该使用

     acces="stream"

并且未格式化。它是在C I / O之后直接建模的,所以理解它不应该有任何问题。它是Fortran 2003的一部分,所有现代编译器都将它实现为AFAIK(即使是像Open64或NEC那样不太先进)。

Fortran和C在同一台机器上使用相同的字节顺序,除非您使用特殊的编译器功能。在平台之间传输文件时可能会出现问题。

如果使用Fortran程序

     access="sequential", form="unformatted"

您将遇到记录分隔符问题。

写为

的文件
     access="direct", form="unformatted"

可以。

答案 1 :(得分:0)

Fortran在其二进制文件中放置一个标题,因此您只能使用Fortran直接读取它们。在Fortran中编写二进制文件时使用form='unformatted'以避免这种情况。阅读未格式化二进制文件的方法显示为here。为了更深入地了解Fortran如何处理二进制I / O,一个很好的起点是this threat

答案 2 :(得分:0)

正如其他人(@cup)问的那样,你是怎么写这个文件的?

Fortran和C之间的IO可以很好地协同工作,因为@Vladimir在写作时要小心使用endianess。如果你没有指明它们都应该是本地写/读。它可以是编译器选项,也可以是Fortran中open的选项。

例如

  • Ifort:-convert big_endian
  • Gfortran:-fconvert=big_endian
  • PGI:-byteswapio

等等。请参考您的编译器手册,找出它的标志。

因此,假设您按如下方式编写文件:

program w
    implicit none

    integer, parameter :: max_i = 10
    integer, parameter :: max_j = 10

    integer :: i, j
    integer :: iunit, stat
    real    :: x(max_i,max_j)

    do j=1,max_j
            do i=1,max_i
                    x(i,j) = (i - 1) + (j -1)*max_i
            end do
    end do

    iunit = 7
    open(unit=iunit, file="data", iostat=stat, &
         form="unformatted")
    if (stat .ne. 0) then
            write(*,*) "unable to create data file"
            stop 1
    end if

    write(iunit) x

    close(iunit)

end program w

如果我们不看文件,

-rw-r--r-- 1 tbrown users 408 Nov 15 13:16 data

注意它是408字节。正如@leeladam所说,Fortran通常在数据的开头和结尾放置一个大小标题,在这种情况下,它使用4字节的记录标记。因此,两个记录标记和100个数据元素为4字节浮点数:

2 * 4 + (10*10*4) = 408

对数据文件进行良好的健全性检查。

然后你可以用C语言阅读它:

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <unistd.h>

int
main(int argc, char **argv)
{

    int ifd = 0;
    int i = 0;
    int j = 0;
    int max_i = 10;
    int max_j = 10;
    int fsize = 0;
    int size = 0;
    int ierr = 0;
    float x[max_i][max_j];


    if ((ifd = open("data", O_RDONLY)) < 0) {
            perror("Unable to open data");
            return(EXIT_FAILURE);
        }

    /* read the data size at the start */
    if ((ierr = read(ifd, &fsize, 1*sizeof(int))) < 0) {
            perror("Size read error");
            close(ifd);
            return(EXIT_FAILURE);
    }

    /* compute the size of our data variable */
    size = max_i * max_j * sizeof(float);

    /* read the data */
    if (fsize != size) {
            printf("file and data size mismatch: %d != %d\n", fsize, size);
            close(ifd);
            return(EXIT_FAILURE);
    }

    if ((ierr = read(ifd, &x, size)) < 0) {
            perror("Data read error");
            close(ifd);
            return(EXIT_FAILURE);
    }

    /* read the data size at the end */
    if ((ierr = read(ifd, &fsize, 1*sizeof(int))) < 0) {
            perror("Size read error");
            close(ifd);
            return(EXIT_FAILURE);
    }

    close(ifd);

    for (i = 0; i <= max_i -1; ++i) {
            for (j = 0; j <= max_j -1; ++j) {
                printf("i: %d j: %d x: %f\n", i, j, x[i][j]);
        }
    }

    return(EXIT_SUCCESS);
}

另请注意,您可以使用od检查文件。

要查看第一个记录标记:

$ od -d -N 4 data
0000000       400       0
0000004

要查看数据:

$ od -j 4 -N 400 -f data
0000004     0.000000e+00    1.000000e+00    2.000000e+00    3.000000e+00
0000024     4.000000e+00    5.000000e+00    6.000000e+00    7.000000e+00
0000044     8.000000e+00    9.000000e+00    1.000000e+01    1.100000e+01

修改

我忘了提及,我更喜欢将Fortran二进制输出写为大端并将其记录下来,以便人们随时了解。然后在C中使用xdr(或ntohl)例程。