用C ++读取一个直接访问fortran未格式化的文件 [英] Reading a direct access fortran unformatted file in C++

查看:470
本文介绍了用C ++读取一个直接访问fortran未格式化的文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在尝试C ++读取一个Fortran编写的二进制文件,但我没有取得太大的成功。编写该文件的Fortran代码不是我自己的,尽管C ++解析例程是。



二进制文件的第一条记录是使用以下语句编写的: ):

  INTEGER var1 var2 var3 
WRITE(12,REC = 1)var1,var2,var3

执行成功读取的Fortran代码片段如下所示:

  open(unit = 10,file =ETC.bin,access ='direct',recl = 24,iostat = iost,status ='old')
read(unit = 10,rec = 1)var1,var2,var3
close(unit = 10)
print *,var1,var2,var3
pre>

在C ++方面,我到目前为止提出了以下内容:

pre > FILE * binfile = fopen(ETC.bin,rb);
fseek(binfile,0,SEEK_END);
long lSize = ftell(binfile);
char * buffer =(char *)malloc(sizeof(char)* lSize);
倒带(binfile);
size_t result = fread(buffer,1,96,binfile);
for(unsigned i = 0; i< = result; i ++){
printf(%f \ n,buffer [i]);
}

不幸的是,我的C ++ printf语句返回了无意义的结果。请注意,我假设Fortran依赖4位单词(例如gfortran编译器),并且如果使用ifort,那么

   - 在编译时需要byterecl 

选项。



我知道结果应该是什么,但我不确定如何在C ++中复制Fortran读取语句的行为。



谢谢为任何和所有帮助!



PS有一个类似的问题发布在这里:阅读fortran二进制文件在C ++中< a>,它指向以下无效链接。没有太多的信息,或者我的Google-Fu很糟糕。 尝试了几件事。



首先是Fortran部分:

  program direct_access 
implicit none
integer,parameter :: UNT = 63347
open(unit = UNT,file ='delme.unf',access ='DIRECT',& $ b $ (UNT,rec = 1)1,2,3
write(UNT,rec = 2)4,5, 6
关闭(UNT)
结束程序direct_access

我写了3个整数,每个4字节,转换为一个记录长度为24字节的未格式化文件。 (注意:我在这里假设记录长度是以字节为单位的,显然这是不能保证的,并且依赖于编译器和系统。)

另外,从我的首选Fortran书籍


未格式化的直接地址文件比格式化的直接存取文件更小且更快,但它们不能在不同类型的处理器之间移植。

(除非 FORM ='FORMATTED'在打开文件时特别指定,否则它将被设置为无格式。)

<测试数据是否写得正确:

  $ hexdump delme.unf 
0000000 0001 0000 0002 0000 0003 0000 0000 0000
0000010 0000 0000 0000 0000 0004 0000 0005 0000
0000020 0006 0000 0000 0000 0000 0000 0000 0000
0000030

看起来不错。请注意,记录长度(24字节)大于数据(3 * 4字节),因此内部有未使用的数据块。



现在到C程序,不是我的专业知识:

  #include< stdio.h> 
#include< stdlib.h>
#include< sys / stat.h>

off_t fsize(const char * filename){
struct stat st;

if(stat(filename,& st)== 0)
return st.st_size;

返回-1;
}

int main(){
int record_size = 24;
int num_records = fsize(delme.unf)/ record_size;
FILE * binfile = fopen(delme.unf,rb);
int * record =(int *)malloc(record_size);
size_t结果; (unsigned j = 0; j fseek(binfile,j * record_size,SEEK_SET);

printf(%i:,j);
result = fread(record,sizeof(int),record_size / sizeof(int),binfile);
for(unsigned i = 0; i< result; i ++){
printf(%i,record [i]);
}
printf(\\\
);
}
free(record);
fclose(binfile);
}

输出:

  0:1 2 3 0 0 0 
1:4 5 6 0 0 0

也很好。



我注意到了几件事:


  • 您的缓冲区类型为 char - 表示每个元素为单个字节。但整数有4个字节。这意味着文件内容被分割成几个元素。

  • 你的Fortran代码设置记录长度为24(字节,我假设),但是3个整数只能使用4个字节,所以有一半的记录没有被使用。如果你有 result 元素,那么缓冲区的索引 / code>需要从 0 result-1

  • 确定文件大小的方式显然不是一个好主意,请参阅 here

  • 您使用%f 作为输出,表示浮动?但我认为这些是整数?



当然,如果您不关心无序读取数据,您可以循环遍历文件:

  #include  
#include< stdio.h>

int main(){
FILE * data = fopen(delme.unf,rb);
int var; $(!feof(data)){
fread(& var,sizeof(int),1,data);
printf(%i,var);
}
printf(\\\
);
fclose(data);
}

肯定有人会帮助你写出比我更好的C代码。

I am currently trying to C++ read a Fortran-written binary file, and I am not having much success. The Fortran code that writes the file is not my own, although the C++ parsing routine is.

The first record of the binary file has been written using the following statement(s):

INTEGER var1 var2 var3
WRITE(12,REC=1) var1,var2,var3

A Fortran snippet that performs a succcesfull read looks like this:

open(unit=10,file="ETC.bin",access='direct',recl=24,iostat=iost,status='old')
read (unit=10,rec=1) var1,var2,var3
close(unit=10)
print*,var1,var2,var3

On the C++ side of things, I have so far come up with the following:

FILE* binfile = fopen("ETC.bin","rb") ;
fseek (binfile,0,SEEK_END) ;
long lSize = ftell (binfile) ;
char* buffer = (char*) malloc (sizeof(char)*lSize) ;
rewind (binfile) ;
size_t result=fread(buffer,1,96,binfile) ;
for (unsigned i = 0; i<=result; i++){
   printf("%f\n",buffer[i]) ;
}

My C++ printf statement, unfortunately, returns nonsense. Note that I am assuming that Fortran is relying on 4 bit words (e.g. gfortran compiler), and that if ifort is used, the

--assume byterecl

option is needed at compile time.

I know what the result should be, but I am not sure as to how to duplicate the behavior of the Fortran read statements in C++.

Thanks for any and all help!

P.S. There is a similar question posted here: reading fortran binary file in c++, which points to the following dead link. Not much information out there, or my Google-Fu is lousy.

解决方案

I'm not very good in C, but I have tried a few things.

First for the Fortran part:

program direct_access
    implicit none
    integer, parameter :: UNT = 63347
    open(unit=UNT, file='delme.unf', access='DIRECT', &
        form='UNFORMATTED', status='REPLACE', recl=24)
    write(UNT, rec=1) 1, 2, 3
    write(UNT, rec=2) 4, 5, 6
    close(UNT)
end program direct_access

I am writing 3 integers, of 4 bytes each, into an unformatted file with a record length of 24 bytes. (Note: I am assuming here that the record length is in bytes, apparently that isn't guaranteed and compiler and system dependent.)

Also, from my preferred Fortran book

Unformatted direct addess files are both smaller and faster than formatted direct access files, but they are not portable between different types of processors.

(Unless FORM='FORMATTED' is specifially given when opening the file, it will be unformatted.)

Test whether the data was written correctly:

$ hexdump delme.unf
0000000 0001 0000 0002 0000 0003 0000 0000 0000
0000010 0000 0000 0000 0000 0004 0000 0005 0000
0000020 0006 0000 0000 0000 0000 0000 0000 0000
0000030

Looks good. Note that the record length (24 bytes) is larger than the data (3*4 bytes), so there are unused data blocks inside.

Now to the C program, not my expertise:

#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>

off_t fsize(const char *filename) {
    struct stat st; 

    if (stat(filename, &st) == 0)
        return st.st_size;

    return -1; 
}

int main(){
    int record_size=24;
    int num_records=fsize("delme.unf") / record_size;
    FILE* binfile = fopen("delme.unf","rb") ;
    int* record = (int*) malloc (record_size) ;
    size_t result ;
    for (unsigned j=0; j < num_records; j++) {
        fseek(binfile, j * record_size, SEEK_SET) ;
        printf("%i : ", j) ;
        result=fread(record,sizeof(int),record_size/sizeof(int),binfile) ;
        for (unsigned i = 0; i<result; i++){
            printf("%i ",record[i]) ;
        }
        printf("\n");
    }
    free(record);
    fclose(binfile);
}

Output:

0 : 1 2 3 0 0 0 
1 : 4 5 6 0 0 0 

Also good.

A few things I noticed:

  • Your buffer is of type char -- meaning a single byte per element. But integers have 4 bytes. That means that the file contents are split into several elements.
  • also, your fortran code sets a record length of 24 (bytes, I assume), but 3 integers only use 4 bytes each, so half of the record is not used. That's why read gives three more zeros.
  • If you have result elements, then the indices of buffer need to go from 0 to result-1.
  • The way you determine the size of the file is apparently not a good idea, see here
  • You're using %f as an output, indicating floats? But I thought these were ints?

Of course, if you don't care about reading the data out-of-order, you can just loop over the file:

#include <stdlib.h>
#include <stdio.h>

int main() {
    FILE* data = fopen("delme.unf", "rb") ;
    int var ;
    while (! feof(data )) {
        fread(&var, sizeof(int), 1, data);
        printf("%i ", var);
    }
    printf("\n");
    fclose(data);
}

There are certainly people that will help you write better C code than I do.

这篇关于用C ++读取一个直接访问fortran未格式化的文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆