Io 读取未格式化的二进制文件:意外输出-Fortran90
前言:我需要弄清楚二进制网格数据文件的结构。根据Fortran例程,我计算出第一条记录由57个字节组成,信息的顺序如下Io 读取未格式化的二进制文件:意外输出-Fortran90,io,fortran,binaryfiles,fortran90,Io,Fortran,Binaryfiles,Fortran90,前言:我需要弄清楚二进制网格数据文件的结构。根据Fortran例程,我计算出第一条记录由57个字节组成,信息的顺序如下 No. of the file :: integer*4 File name :: char*16 file status :: char*3 (i.e. new, old, tmp) .... so forth (rest is clear from write statement in the program) 现在,为了进行测试,我编写了一个简单的程序,如下所示:(我没
No. of the file :: integer*4
File name :: char*16
file status :: char*3 (i.e. new, old, tmp)
.... so forth (rest is clear from write statement in the program)
现在,为了进行测试,我编写了一个简单的程序,如下所示:(我没有包括所有的参数)
令我惊讶的是,当我将声明部分更改为
integer*4 :: x, nclat, nclon
character*16 :: y
character*3 :: z
real*4 :: lat_gap, lon_gap, north_lat, west_lat
integer*2 :: gridtype
它给了我一些正确的信息,尽管不是全部!我不明白。如果有人解释这种现象,将有助于我提高Fortran知识
此外,由于机器陈旧且不受支持,我无法使用
ACCESS=stream
,因此我认为以上是确定文件结构的唯一可能性。根据您的回复和其他人的评论,我认为您的问题可能是对Fortran“记录”的误解:
您说您有一个二进制文件,其中每个条目(您说的是记录,但稍后会详细介绍)是57字节
问题是Fortran I/O中的“记录”并不是您所期望的来自C(或其他任何地方)背景的记录。请参阅英特尔提供的以下文档,其中对不同的访问模式进行了很好的解释:
流
,那么实际上没有简单、轻松的方法来读取没有记录信息的二进制文件
需要C编译器的一个可能的解决方案是在从Fortran调用的C函数中执行IO,“最小”示例:
main.f90:
program main
integer, parameter :: dp = selected_real_kind(15)
character(len=*), parameter :: filename = 'test.bin'
real(dp) :: val
call read_bin(filename, val)
print*, 'Read: ', val
end program
改为c:
#include <string.h>
#include <stdio.h>
void read_bin_(const char *fname, double *ret, unsigned int len)
{
char buf[256];
printf("len = %d\n", len);
strncpy(buf, fname, len);
buf[len] = '\0'; // fortran strings are not 0-terminated
FILE* fh = fopen(buf, "rb");
fread(ret, sizeof(double), 1, fh);
fclose(fh);
}
使用/write
创建二进制文件,然后查看Fortran代码如何使用/readbin
读回该文件
这可以扩展到不同的数据类型,以基本模拟access=stream
。最后,如果您可以重新编译原始Fortran代码,以不同的方式输出数据文件,这将是最简单的解决方案,因为这是一个非常粗糙的破解
最后,一个进入未知数据格式的技巧:工具od
是您的朋友,请查看其手册页。它可以直接将二进制表示转换为各种不同的本机数据类型。尝试上面的示例(z在右侧列中添加字符表示,在这里不是很有用,通常是):
不应直接输入直接访问的记录长度,如
200
。处理器不必使用字节作为长度单位,应该使用inquire
语句来获取它。另外,当你之前声明的是57
字节时,为什么要使用200
?顺便说一句,没有哪个mod或admin进行向下投票,这是所有用户之间的反馈。当你获得足够的声誉时,你还可以投票选择其他问题和答案。还有,不要因为一张否决票而生气,那是会发生的。试着找出什么能激发它。许多用户害怕告诉你他们为什么投票否决了这篇文章,因为有些用户对他们进行了报复。弗拉基米尔,你说得对极了。我一开始就是这么做的。在open语句之前,我在open语句之前使用了INQUIRE(file=filename,recl=irec)
,但它给了我一个错误。RECL说明符为零或为负。所以,在向下投票时,我没有感到愤怒或任何事情。这是令人沮丧的。不管怎么说,我觉得自己像个傻瓜,然后对你的问题投了反对票,这只会增强我的傻瓜感!此外,如果没有记录,你甚至没有机会提高,也不能保证OP将来不会再犯同样的错误!你知道,这是一个恶性循环!您无法从文件中获取长度,必须从记录INQUIRE(iolength=irec)x、y、z、lat_gap、lon_gap、north_lat、west_lat、nclat、nclon、gridtyp
中写入的变量中获取长度。谢谢Markus,我将在下周尝试。我刚看到你的反应。关于第二个问题(补充问题)。在我的搜索过程中,我遇到了hextump选项(您已经提到了od)。如果我使用hextump转换工具来读取文件,有意义吗?我还发现MATLAB可以读取这样的文件。
#include <string.h>
#include <stdio.h>
void read_bin_(const char *fname, double *ret, unsigned int len)
{
char buf[256];
printf("len = %d\n", len);
strncpy(buf, fname, len);
buf[len] = '\0'; // fortran strings are not 0-terminated
FILE* fh = fopen(buf, "rb");
fread(ret, sizeof(double), 1, fh);
fclose(fh);
}
#include <stdio.h>
int main() {
double d = 1.234;
FILE* fh = fopen("test.bin", "wb");
fwrite(&d, sizeof(double), 1, fh);
fclose(fh);
}
gcc -o write write.c
gcc -c -g read.c
gfortran -g -o readbin main.f90 read.o
od -t fDz test.bin