问题
Unless using the new-ish stream-access available in F2003, Fortran classically considers files to be a sequence of records. If a file is connected for direct-access one can access any record in any order by specifying the record number. For example:
open(newunit=funit, file=filename, form='unformatted', access='direct', &
recl=64, status='old')
read(funit, rec=2) data
close(funit)
So this sounds great...however, I'm not sure I understand the RECL parameter and how direct-access can be used effectively if the correct record length isn't already known. From the docs (various Intel Fortran versions):
All records have the length specified by the RECL option in the OPEN statement.
In other words, direct-access allows access to data in an amount equal to or less than RECL, while moving through the file in increments of RECL. That is, you can specify any value you like (equal to or less than the size of the file, I assume). I guess that's obvious in hindsight...yet I was hoping that the appropriate RECL was discoverable in some way.1 Perhaps I'm doing this wrong, but I would like to get the data from the specified record only - not more, not less.
Aside from encoding the appropriate RECL
value in a 'header' section of the file, is there a way to access a single record at a time with a file connected for unformatted (or even formatted) direct-access if the correct record length is not known beforehand? What tricks-of-the-trade are used to do this?
1 I had hoped inquire(funit, recl=rl)
would provide the appropriate RECL, but if the file was connected for direct-access, it returns the RECL value specified when the file was opened. If connected for sequential-access, it seems that it returns the maximum record length allowed (?), 2040 in my case.
回答1:
Indeed, it is not possible to find it out from looking at the file, because that is just the data and (normally) no record markers, so the compiler just sees a stream of unstructured bytes. At least in byte oriented computers. I know nothing about record oriented filesystems, only that they exist.
If you know what kind of data is stored in the direct access record, you can inquire the compiler by asking not about the file, but about the data.
For example, if the record consists of variables a
, b
, c
, whatever they are,
!just an example
real :: a(10)
type(my_type) :: b
character(5) :: c(3)
you ask how large such a record is
inquire(iolength=rl) a, b, c
and then you connect your file with recl=rl
open(newunit=funit, file=filename, form='unformatted', access='direct', &
recl=rl, status='old')
See, for example, Why direct access I/O works incorrectly with Intel Visual Fortran
Be careful, the RECL value is not portable and will vary between compilers. Some measure it in bytes and some in 4-byte words. I just remember that gfortran and ifort differ, not which one is which. And I don't care which one is which.
If you find yourself specifying RECL with a magic constant as in recl=64
you are doing something wrong, because this will not work in a different compiler. You should always have a variable, not a fixed number.
来源:https://stackoverflow.com/questions/43898711/how-to-access-a-single-record-with-fortran-unformatted-direct-access-when-the-ap