写入和读取访问权限= fortran中的流文件

时间:2013-01-15 11:50:12

标签: fortran

我有一个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进行编译,但我没有收到任何错误消息。

有谁知道为什么会这样?

2 个答案:

答案 0 :(得分:0)

首先,我不认为您需要关闭并重新打开输出文件。 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'

答案 1 :(得分: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文件时,也可以附加文件,你不必为此使用流。