1

我有一个 shell 脚本,我从中将一个二进制文件传递给一个 fortran 程序,这样

Mth=$1
loop=1
it=1
while test $it -le 12
do 
    Mth=`expr $Mth + $loop`
    file="DataFile"$Mth".bin"
    ./fort_exe ${Yr} ${nt} ${it} 

# Increment loop
it=`expr $it + 1`
done

该脚本用于将 do 循环中的 12 个文件传递给 fortran 程序。在 fortran 程序中,我读取了从 shell 脚本传递的二进制文件,并尝试编写第二个文件,它将在单个文件中编译从连续文件中读取的所有数据,例如

 !Open binary file passed from shell script
 open(1,file='Datafile'//TRIM{Mth)//.bin',action='read',form='unformatted',access='direct', &
 recl=4*x*y, status='old')

! Open write file for t 1. The status is different in t 1 and t > 1 so I open it twice: I guess there is a more elegant way to do this...
 open(2,file='Newfile.bin',action='write',form='unformatted', &
 access='stream', position='append', status='replace')
 irec = 0

 do t = 1, nt
 ! Read input file
  irec = irec + 1
  read(1,rec=irec) val(:,:)

 ! write output file
 irecW= irec + (imonth-1)*nt

 if ( t .eq. 1) write(2,pos=irecW) val(:,:)

 ! Close file after t = 1, update the status to old and reopen. 
 if ( t .eq. 2) then
    close (2)
    open(2,file='Newfile.bin',action='write',form='unformatted', &
         access='stream', position='append',status='old')
  endif

  if ( t .ge. 2) write(2,pos=irecW) val(:,:)

  enddo

我可以从第一个文件中读取二进制数据没有问题,但是当我尝试从另一个程序中读取我在第一个程序中写入的文件中的二进制数据时

 open(1,file='Newfile.bin',action='read',form='unformatted', &
 access='stream', status='old')

 irec=0
 do t = 1, nt
! Read input file
     irec = irec + 1
     read(1,pos=irec) val(:,:)
     write(*,*) val(:,:)
 enddo

val(:,:) 只不过是一个零列表。这是我第一次使用 access=stream,我相信这是我可以使用 position='append' 的唯一方法。我尝试使用 gfortran 和 ifort 进行编译,但没有收到任何错误消息。

有谁知道为什么会这样?

4

2 回答 2

1

首先,我认为您不需要像现在这样关闭并重新打开输出文件。说明status符仅与open它出现的语句相关:如果它存在,将在打开同名的新文件之前replace删除。Newfile.bin状态隐式更改为old,但这不会影响对文件执行的任何操作。

但是,由于您的 Fortran 代码不知道您运行了 12 次,因此您应该有办法确保文件仅在第一次被替换后才被打开old;否则,Newfile.bin将仅包含来自最后处理的文件的信息。

至于读入错误的值,这很可能是因为直接访问(您可以选择记录长度)和流访问(您不能)之间的差异。通过流访问,数据被存储为一系列“文件存储单元”。它们的大小通常取决于编译器,但可以通过模块iso_fortran_env作为file_storage_size; 它通常是 8 位。这意味着每个条目通常会占用多个存储单元,因此您必须注意使用说明pos =符进行的读取或写入不会访问错误的存储单元。


编辑:
使用流访问编写和读取一些示例代码:

program stream
  use, intrinsic :: iso_fortran_env
  implicit none

  integer :: i, offset
  real(real32), dimension(4,6) :: val, nval

  open(unit=2, file='Newfile.bin', action='readwrite', form='unformatted', &
     access='stream', status='replace')

  do i = 1,2
    call random_number(val)
    write(2) val
  enddo

  ! The file now contains two sequences of 24 reals, each element of which
  ! occupies the following number of storage units:
  offset = storage_size(val) / file_storage_size

  ! Retrieve the second sequence and compare:
  read(2, pos = 1 + offset*size(val)) nval
  print*, all(nval == val)

  close(2)
end program

true应该打印到屏幕上。

另请注意,不一定要指定pos将数据写入文件的时间,因为文件将自动定位到读取或写入的最后一条记录之外。


也就是说,如果您需要以非顺序方式访问数据,则直接或流访问是最有益的。如果您只需要将输入文件合并为一个,则使用顺序访问编写输出文件可能会更容易,您还可以为此指定reclposition = 'append'

于 2013-01-15T17:33:15.657 回答
0

inquire您可以使用以下语句在标准 Fortran 中检查文件是否存在:

logical :: exist

inquire(file="test.dat", exist=exist)
if (exist) then
  print *, "File test.dat exists"
else
  print *, "File test.dat does not exist"
end if

或者,您可以查看提供类似 libc 的文件操作例程的modFileSys库。

至于附加和流:当您使用基于“经典”记录的 fortran 文件时,也可以附加文件,您不必为此使用流。

于 2013-01-16T12:31:52.770 回答