Fortran如何将未知大小的整份文件内容读取到数组中
问题1:单行超长基因序列文件读取错误原因及修正
错误分析
你原有代码的核心问题有两处:
- 第一行
read(1,*) fileSize逻辑完全错误:你的输入文件第一行是基因序列,没有提前存储文件大小数值,这行代码会尝试把字符串转成整数,直接触发运行时错误。 - 用列表导向输入(
read(*,*)格式)读取字符内容时,默认会以 whitespace、换行符作为分隔符截断内容,即使你绕过了第一个错误,也没法完整读取超长单行序列。
修正方案
用inquire语句直接获取文件大小,搭配流访问模式直接读取全部字节内容,适配任意长度的单行文本:
PROGRAM FOO implicit none character, allocatable :: input(:) integer :: fileSize, openStat, readStat ! 打开文件时指定流访问模式,直接按字节读写,不受换行/格式限制 open(unit=10, file='input.txt', status='old', action='read', & access='stream', form='unformatted', iostat=openStat) if (openStat /= 0) error stop '文件打开失败' ! 直接查询文件大小,不需要读取文件内容 inquire(unit=10, size=fileSize) allocate(input(fileSize), stat=readStat) if (readStat /= 0) error stop '内存分配失败' ! 流模式下无格式读取全部字节 read(10) input close(10) ! 输出验证,如果文件末尾有换行符不需要的话可以自己截取掉 print *, input END PROGRAM FOO
注:如果你的文件末尾包含换行符,输出最后会多一个空字符/换行,按需截取前fileSize-1或fileSize-2个字符即可(取决于系统换行符是1字节还是2字节)
问题2:多行文本文件的读取方案
实现思路
不需要强制用二维可分配数组,Fortran 2003及以后支持延迟长度字符数组,和Java的String数组功能一致,每个元素可以存储不同长度的行内容,使用更灵活。
读取逻辑确实需要用到iostat参数判断是否读到文件末尾,常规实现步骤:
- 第一次遍历文件,统计总行数
- 分配对应长度的延迟长度字符数组
- 第二次遍历文件,逐行读取存入数组即可
如果你不想遍历两次文件,也可以先读取全部内容到一维字符数组,再按换行符拆分到行数组,效率更高。
示例代码
PROGRAM READ_MULTI_LINE implicit none character(len=:), allocatable :: lines(:) character(len=1024) :: buffer integer :: fileUnit, ioStat, lineCount, i ! 第一步:统计行数 open(newunit=fileUnit, file='input.txt', status='old', action='read') lineCount = 0 do read(fileUnit, '(A)', iostat=ioStat) buffer if (ioStat /= 0) exit lineCount = lineCount + 1 end do rewind(fileUnit) ! 回到文件开头 ! 第二步:分配数组 allocate(character(len=1024) :: lines(lineCount)) ! 第三步:逐行读取 do i = 1, lineCount read(fileUnit, '(A)') lines(i) ! 可以自行trim去掉尾部空格,或者调整buffer长度适配最长行 end do close(fileUnit) ! 测试输出前5行 do i = 1, min(5, lineCount) print *, trim(lines(i)) end do END PROGRAM READ_MULTI_LINE
注:如果你的单行长度超过1024,调大buffer的长度即可;如果要适配任意行长度,可以每次读取时先获取当前行长度再分配对应长度的元素,逻辑会稍复杂一点
内容的提问来源于stack exchange,提问作者boardkeystown
相关产品推荐
相关产品推荐

