我想从文件中获取数据,该文件的数据内容可能有不同的大小。但是,结构非常简单。 3列和未定义的行数。我认为使用可分配的多维数组和显式的DO循环让我解决了我的问题。这是我到目前为止的代码
program arraycall
implicit none
integer, dimension(:,:), allocatable :: array
integer :: max_rows, max_cols, row, col
allocate(array(row,col))
open(10, file='boundary.txt', access='sequential', status='old', FORM='FORMATTED')
DO row = 1, max_rows
DO col = 1, max_cols
READ (10,*) array (row, col)
END DO
END DO
print *, array (row,col)
deallocate(array)
end program arraycall
现在我面临的问题是,我不知道如何定义这些max_rows和max_cols,这些因为它的大小未知而产生共鸣。
示例文件可能看起来像
11 12 13
21 22 23
31 32 33
41 42 43
所以我想出了动态估计文件记录长度的方法。更新以供将来引用他人
!---------------------------------------------------------------------
! Estimate the number of records in the inputfile
!---------------------------------------------------------------------
open(lin,file=inputfile,status='old',action='read',position='rewind')
loop1: do
read(lin,*,iostat=eastat) inputline
if (eastat < 0) then
write(*,*) trim(inputfile),": number of records = ", numvalues
exit loop1
else if (eastat > 0 ) then
stop "IO-Error!"
end if
numvalues=numvalues+1
end do loop1
!-----------------------------------------------------------------------
! Read the records from the inputfile
!-----------------------------------------------------------------------
rewind(lin)
allocate (lon(numvalues),lat(numvalues),value(numvalues))
do i=1,numvalues
read(lin,*) lon(i),lat(i),value(i)
end do
close(lin)
答案 0 :(得分:2)
我认为你有3个选项,其中两个已被描述:
两次读取文件。首先读取行数,然后分配和读取值。正如您所说,如果I / O时间相关,则效率低下。
正如@AlexanderVogt建议的那样,估计最大行数。在所有代码中,您不需要随身携带这个大矩阵。您可以定义第二个数组并执行类似的操作(基于@AlexanderVogt代码):
allocate(array2(3,tot_rows))
array2 = array(:, :tot_rows)
deallocate(array)
不幸的是,我担心您需要2个不同的阵列,因为您无法就地调整大小。这也意味着,如果array
和arrray2
很大,您将会在很短的时间内使用大量内存。
使用链接列表。这是最优雅的解决方案,允许您只需一次读取文件,而无需预先分配数组。但它是最难编码的。这是一个适用于其中一个数组的简单示例。您需要三个链接列表或一个链接列表:
integer, dimension(3) :: data
如果您希望它与3列一起使用。
链接列表代码:
program LinkedList
implicit none
integer :: i, eastat, value, numvalues
type node
integer :: data
type( node ), pointer :: next
end type node
integer, dimension(:), allocatable :: lon
type( node ), pointer :: head, current, previous
nullify( head ) ! Initialize list to point to no target.
open(10,file='data.dat',status='old',action='read', position='rewind')
numvalues = 0
do
read(10,*,iostat=eastat) value
if (eastat < 0) then
write(*,*) "number of records = ", numvalues
exit
else if (eastat > 0 ) then
stop "IO-Error!"
end if
allocate( current )
current%data = value
current%next => head
head => current
numvalues=numvalues+1
end do
close(10)
! The list is read. You can now convert it into an array, if needed for
! numerical efficiency
allocate(lon(numvalues))
current => head
! You could transverse the list this way if you hadn't kept numvalues
!do while ( associated( current ) )
do i= numvalues, 1, -1
lon(i) = current%data
previous => current
current => current%next
! head => current
deallocate(previous)
end do
! Output the list, deallocating them after use.
print *,"lon = ", lon
end program LinkedList
答案 1 :(得分:1)
您可以定义最大允许的行数,并使用iostat
检查文件的结尾(或错误):
program arraycall
implicit none
integer, dimension(:,:), allocatable :: array
integer :: row
integer :: stat ! Check return values
! Define max. values
integer,parameter :: max_rows=1000
integer,parameter :: max_cols=3 ! As stated in the question
! Total number of rows in the file
integer :: tot_rows
allocate( array(max_cols,max_rows), stat=stat)
! Always a good idea to check the return value
if ( stat /= 0 ) stop 'Cannot allocate memory!'
open(10, file='boundary.txt', access='sequential', &
status='old', FORM='FORMATTED')
DO row = 1, max_rows
! You can directly read in arrays!
READ (10,*,iostat=stat) array(:,row)
if ( stat > 0 ) then
stop 'An error occured while reading the file'
elseif ( stat < 0 ) then
tot_rows = row-1
print *, 'EOF reached. Found a total of ', tot_rows, 'rows.'
exit
endif
END DO
close(10)
! Do stuff, e.g. re-allocate the array
print *,array(:,:tot_rows)
deallocate(array)
end program arraycall
iostat > 0
是错误,iostat < 0
是文件结束(或某些编译器的记录结束)。