Fortran 90读取含冒号的CSV文件报错,如何解决?
Fortran 90读取CSV时因字段含空格/冒号触发list-directed I/O语法错误的解决方法
报错信息:
forrtl: severe (59): list-directed I/O syntax error, unit 21, file /data3/khee/data/AWS/ASCII/STATION/2021/csvfile/test.csv Image PC Routine Line Source a.out 000000000043B9EE Unknown Unknown Unknown a.out 0000000000412AB0 Unknown Unknown Unknown a.out 00000000004036D3 Unknown Unknown Unknown a.out 00000000004034DE Unknown Unknown Unknown libc-2.17.so 000000333901F84D __libc_start_main Unknown Unknown a.out 00000000004033E9 Unknown Unknown Unknown原代码:
program read_data implicit none integer :: HSID, DSID real :: HLAT, HLON, HALT, DTEMP, DWDEG, DWSPD, DPRCP, DSPRS, DMSLP, DHMD, DSR, DSRH character(len=16) :: DATE open(21,file='/data3/khee/data/AWS/ASCII/STATION/2021/csvfile/test.csv',form='formatted',access='sequential',status='old') 10 read(21,*,end=90) DSID, DATE, DTEMP, DWDEG, DWSPD, DPRCP, DSPRS, DMSLP, DHMD, DSR, DSRH write(*,*) DSID, DATE, DTEMP, DWDEG, DWSPD, DPRCP, DSPRS, DMSLP, DHMD, DSR, DSRH go to 10 90 continue write(*,*) "EOF" stop end program read_data输入行示例:
848,2021-01-01 00:00,-4.1,9.1,2,0,,,,0,0
问题本质
你使用的列表式I/O(read(21,*))默认将空格、逗号、制表符等都视为字段分隔符。DATE字段2021-01-01 00:00中的空格会被当成分隔符,导致程序仅将2021-01-01读入DATE变量,后续的00:00会被当作下一个字段,但该字段需要匹配实数类型的DTEMP,冒号无法被解析为实数,最终触发语法错误。冒号是表象,核心是列表式读取的分隔规则与CSV结构不匹配。
解决方案
方案一:修改OPEN语句,指定仅用逗号作为分隔符
这是改动最小的方法,只需在OPEN语句中添加delim='comma'选项,强制列表式I/O仅将逗号视为字段分隔符,空格和冒号会被保留在字符字段中:
open(21,file='/data3/khee/data/AWS/ASCII/STATION/2021/csvfile/test.csv',& form='formatted',access='sequential',status='old', delim='comma')
修改后,原有的read(21,*,end=90)语句可以正常工作:DATE字段会完整读取2021-01-01 00:00,后续字段也能正确匹配对应类型。
方案二:先读取整行,再用内部文件解析
如果CSV格式更复杂(比如字段包含引号或嵌套逗号),可以先将整行读取到字符变量,再通过内部文件指定格式解析,精准控制每个字段的读取规则:
program read_data implicit none integer :: DSID real :: DTEMP, DWDEG, DWSPD, DPRCP, DSPRS, DMSLP, DHMD, DSR, DSRH character(len=16) :: DATE character(len=256) :: line ! 存储整行内容,长度可根据实际调整 open(21,file='/data3/khee/data/AWS/ASCII/STATION/2021/csvfile/test.csv',& form='formatted',access='sequential',status='old') 10 read(21, '(A)', end=90) line ! 读取整行到字符变量 ! 用内部文件解析,格式字符串匹配CSV的逗号分隔结构 read(line, '(I0, ",", A16, ",", F0.0, ",", F0.0, ",", I0, ",", F0.0, ",", & & F0.0, ",", F0.0, ",", F0.0, ",", I0, ",", I0)') & & DSID, DATE, DTEMP, DWDEG, DWSPD, DPRCP, DSPRS, DMSLP, DHMD, DSR, DSRH write(*,*) DSID, DATE, DTEMP, DWDEG, DWSPD, DPRCP, DSPRS, DMSLP, DHMD, DSR, DSRH go to 10 90 continue write(*,*) "EOF" stop end program read_data
说明:I0和F0.0表示自动匹配整数/实数的长度,","用于跳过字段间的逗号,空字段会被解析为对应类型的默认值(如实数0、整数0)。
内容的提问来源于stack exchange,提问作者Khee
相关产品推荐
相关产品推荐

