我有一个使用Compaq Visual Fortran编译器(大端)生成的未格式化二进制文件。
以下是一些文档说明的内容:
二进制文件以包含数据数组的一般格式编写,并以描述符记录为首:
尝试读取此类数据
module modbin
type rectype
character(len=8)::key
integer::data_count
character(len=4)::data_type
logical::is_int
integer, allocatable:: idata(:)
real(kind=8), allocatable::rdata(:)
end type
contains
subroutine rec_read(in_file, out_rec)
integer, intent(in):: in_file
type (rectype), intent(inout):: out_rec
!
! You need to play around with this figure. It may not be
! entirely accurate - 1000 seems to work, 1024 does not
integer, parameter:: bsize = 1000
integer:: bb, ii, iimax
! read the header
out_rec%data_count = 0
out_rec%data_type = ' '
read(in_file, end = 20) out_rec%key, out_rec%data_count,
out_rec%data_type
! what type is it?
select case (out_rec%data_type)
case ('INTE')
out_rec%is_int = .true.
allocate(out_rec%idata(out_rec%data_count))
case ('DOUB')
out_rec%is_int = .false.
allocate(out_rec%rdata(out_rec%data_count))
end select
! read the data in blocks of bsize
bb = 1
do while (bb .lt. out_rec%data_count)
iimax = bb + bsize - 1
if (iimax .gt. out_rec%data_count) iimax = out_rec%data_count
if (out_rec%is_int) then
read(in_file) (out_rec%idata(ii), ii = bb, iimax)
else
read(in_file) (out_rec%rdata(ii), ii = bb, iimax)
end if
bb = iimax + 1
end do
20 continue
end subroutine rec_read
subroutine rec_print(in_recnum, in_rec)
integer, intent(in):: in_recnum
type (rectype), intent(in):: in_rec
print *, in_recnum, in_rec%key, in_rec%data_count, in_rec%data_type
! print out data
open(unit=12, file='reader.data' , status='old')
write(12,*)key
!write(*,'(i5')GEOMINDX
!write(*,'(i5')ID_BEG
!write(*,'(i5')ID_END
!write(*,'(i5')ID_CELL
!write(*,'(i5')TIME_BEG
!write(*,'(i5')SWAT
!format('i5')
!end do
close(12)
end subroutine rec_print
end module modbin
program main
use modbin
integer, parameter:: infile=11
! fixed size for now - should really be allocatable
integer, parameter:: rrmax = 500
type (rectype):: rec(rrmax)
integer:: rr, rlast
open(unit=infile, file='TEST1603.SLN0001', form='UNFORMATTED',
status='OLD', convert='BIG_ENDIAN')
rlast = 0
do rr = 1, rrmax
call rec_read(infile, rec(rr))
if (rec(rr)%data_type .eq. ' ') exit
rlast = rr
call rec_print(rr, rec(rr))
end do
close(infile)
end program main
此代码可以编译并顺利显示
并且不会产生任何错误,但这会写入输出文件
没有显示有用的数值
相关文件可用here
正确的WRITE语句应生成一个像这样的文件here
我的写声明输出的文件类型错误吗? ,如果是的话,最好的方法是什么? 谢谢
答案 0 :(得分:0)
以上注释试图将您定向到代码中的(至少)两个问题之一。在子程序rec_print
中,您有write(12,*)key
用来编写write(12,*)in_rec%key
的位置(至少我想这就是您想要的。)
我发现的另一个问题是rec_print使用status='old'
打开reader.data,然后在写入密钥后将其关闭。 (此处使用old
表示该文件已存在。)每次调用rec_print时,将打开该文件,覆盖第一条记录,然后关闭该文件。解决此问题的一种方法是使用status='unknown'. position='append'
,尽管在主程序中一次打开文件并让子例程写入文件会更有效。
如果进行这些更改,我将进入数据文件:
INTEHEAD
GEOMETRY
GEOMINDX
ID_BEG
ID_END
ID_CELL
TIME_BEG
SWAT
关于CONVERT =和派生类型的附带注释:您的程序不受此影响,但是在处理如何使用CONVERT =读取派生类型记录方面存在编译器差异。我认为gfortran会根据其类型转换每个组件,但是我知道Intel Fortran不会转换整个派生类型的读取(或写入)。您正在阅读在两个编译器中都可以使用的单个组件,所以很好,但是我认为值得一提。
如果您想知道为什么Intel Fortran会这样做,这是由于STRUCTURE / RECORD的VAX FORTRAN(CONVERT =来源)和可能使用UNION / MAP(在标准Fortran中不可用)所致。使用联合,无法知道应如何转换特定组件,因此它仅传输字节。我曾向英特尔团队建议,如果不存在UNION,可以放宽这点,但是我确定优先级非常低。