我认为这是一个非常基本的问题,但我似乎无法找到答案。我试图读取以下格式的文件:
1 filedir/i03j12_fort.4
71 filedir/i04j01_fort.4
224 filedir/i04j02_fort.4
我使用以下命令获取初始整数,加上' i'和' j'文件名中的值(ldir是一个包含filedir长度的字符串)。
read(filenumber,'(i6,'//ldir//'x,i2,x,i2)') n,pix_i,pix_j
问题是整数之前的空白量在文件之间有所不同,所以我每次都必须手动更改宽度。我还尝试不指定格式,并读取整个文件名作为一个字符串,即
read(filenumber,*) n, filename
但是文件名会返回奇怪的字符(虽然n可以工作)。
是否有任何格式语句将读取整数到它找到的第一个空格,以替换' i6'我上面有什么?
谢谢!
答案 0 :(得分:0)
不 - 您需要手动处理文件"#34;。把它读成一个字符串,去寻找第一个非空白,然后去寻找下一个空白,然后使用内部的io来读取相关的位等。
正如您所发现的,列出定向io(使用*
作为格式说明符)具有一些令人惊讶的功能 - 其中之一是输入中的斜杠字符(/
)意味着"停止阅读此处并将剩余的变量保留在IO列表中,因为它们是"。当你有包含斜杠的路径时,这不能很好地工作!
只是为了好玩......
PROGRAM read_some_things
IMPLICIT NONE
! Some number bigger than most of the lines to be read.
INTEGER, PARAMETER :: line_buffer_size = 28
! Index of the start of the value of i in filename.
INTEGER, PARAMETER :: pos_i_in_filename = 10
! Index of the start of the value of j in filename.
INTEGER, PARAMETER :: pos_j_in_filename = 13
CALL process_a_file
CONTAINS
SUBROUTINE process_a_file
INTEGER :: unit ! Unit number for IO.
CHARACTER(:), ALLOCATABLE :: line ! A line from the file.
INTEGER :: iostat ! IOSTAT code.
CHARACTER(256) :: iomsg ! IOMSG to go with IOSTAT
INTEGER :: n, i, j ! Numbers of interest.
OPEN( NEWUNIT=unit, FILE='2015-01-09 read_some_things.txt', &
ACTION='READ', STATUS='OLD', POSITION='REWIND' )
DO
CALL read_a_line(unit, line, iostat, iomsg)
IF (IS_IOSTAT_END(iostat)) EXIT
IF (iostat /= 0) THEN
PRINT "('Error number ',I0,' reading file: ',A)", &
iostat, TRIM(iomsg)
ERROR STOP ':('
END IF
! What to do with an empty record?
! IF (LEN_TRIM(line) == 0) CALL Start_WW3
CALL chop_a_line(line, n, i, j)
PRINT "(2X,I0,1X,I0,1X,I0)", n, i, j
END DO
CLOSE(unit)
END SUBROUTINE process_a_file
! Parse a line into numbers of interest.
SUBROUTINE chop_a_line(line, n, i, j)
CHARACTER(*), INTENT(IN) :: line ! The line to chop.
INTEGER, INTENT(OUT) :: n ! Things we got...
INTEGER, INTENT(OUT) :: i
INTEGER, INTENT(OUT) :: j
! Various significnat character positions in the line.
INTEGER :: first_non_blank_pos
INTEGER :: next_blank_pos
INTEGER :: before_filename_pos
! Buffer for assembling a format specification.
CHARACTER(100) :: fmt
! Find start of first non-blank group.
first_non_blank_pos = VERIFY(line, ' ')
! Tolerate its non-existence - this may be zero.
! Find start of the following blank group, starting from after
! the beginning of the first non-blank group.
next_blank_pos = SCAN(line(first_non_blank_pos+1:), ' ')
! It had better exist. If it doesn't, confuse user.
IF (next_blank_pos == 0) ERROR STOP 'I didn''t draw any blanks'
next_blank_pos = next_blank_pos + first_non_blank_pos
! Find start of the second group of non-blanks, backup one.
before_filename_pos = VERIFY(line(next_blank_pos:), ' ')
! It had better exist. If it doesn't, annoy user.
IF (before_filename_pos == 0) ERROR STOP 'Line in file with no file!'
! Note -2 to backup one and remember position before filename.
before_filename_pos = before_filename_pos + next_blank_pos - 2
! This specifies:
! - read all prior to filename as integer,
! - then skip to start of i, read I2,
! - then skip to start of j, read I2.
WRITE (fmt, "('(I',I0,',T',I0,',I2,T',I0,',I2)')") &
before_filename_pos, &
before_filename_pos + pos_i_in_filename, &
before_filename_pos + pos_j_in_filename
READ (line, fmt) n, i, j
END SUBROUTINE chop_a_line
! Read a record into a character variable. Pretty common task...
SUBROUTINE read_a_line(unit, line, iostat, iomsg)
INTEGER, INTENT(IN) :: unit ! Unit to read from.
CHARACTER(:), INTENT(OUT), ALLOCATABLE :: line ! The record read.
INTEGER, INTENT(OUT) :: iostat ! +ve on error, -ve on eof.
CHARACTER(*), INTENT(OUT) :: iomsg ! IOMSG if iostat /= 0
! Buffer to read record fragment.
CHARACTER(line_buffer_size) :: buffer
INTEGER :: size ! Amount read per read.
line = ''
DO
! Read a bit without always advancing to the next record.
READ ( unit, "(A)", ADVANCE='NO', SIZE=size, IOSTAT=iostat, &
IOMSG=iomsg ) buffer
IF (iostat > 0) RETURN ! Bail on fail.
! Philosophical discussion about whether EOF is possible
! and SIZE /= 0 goes here (consider STREAM access).
line = line // buffer(:size) ! Append what we got.
! Exit loop on end of file or end of record.
IF (iostat < 0) EXIT
END DO
! End of record is expected, not a relevant condition to return.
IF (IS_IOSTAT_EOR(iostat)) iostat = 0
END SUBROUTINE read_a_line
END PROGRAM read_some_things
答案 1 :(得分:0)
为了完整性,这是我选择的解决方案,它依赖于整数后面的字符串始终以&#39; /&#39;开头的事实。 (因为它是文件路径):
! first determine how much whitespace is around the first integer
! and store this as string ln
read(20, '(a)') filestring
write(ln, "(I1)") INDEX(filestring, ' /')-1
rewind(20)
! use ln to as the integer width
read(filenumber,'(i'//ln//','//ldir//'x,i2,x,i2)') n,pix_i,pix_j