我试图用Matlab的fscanf函数读取小配置文件中包含的信息。该文件的内容是;
YAcex: 1.000000
YOx: 1.000000
KAce: 1.000000
用于解析文件的matlab代码是;
fh = fopen('parameters', 'r');
fscanf(fh, 'YAcex: %f\n')
fscanf(fh, 'YOx: %f\n')
fscanf(fh, 'KAce: %f\n')
fclose(fh);
调用此脚本时,只能正确读取“YAcex”行; fscanf为其他两行返回[]
。如果切换YOx和KAce线(在YOx之前KAce),fscanf将正确读取所有线。
有人可以解释这种行为吗?
补充信息:输入文件中的换行符是简单的换行符(\ n字符,没有\ r \ n字符)。
答案 0 :(得分:8)
您的问题是您只想在每次调用fscanf
时读取一个值,但默认情况下它会尝试读取尽可能多的值。请注意文档中的摘录:
fscanf
函数在整个文件中重新应用格式,并将文件指针定位在文件结束标记处。如果fscanf
无法将formatSpec
与数据匹配,则只会读取匹配并停止处理的部分。
这意味着第一个调用正确读取了文件的第一行,但随后也尝试读取下一行,找不到与其format specifier匹配的完全匹配。它会为下一行找到部分匹配,其中Y
的第一个YOx:
与格式说明符中的YAcex:
的开头匹配。此部分匹配将文件指针直接放在 Y
YOx:
之后,导致下一次调用fscanf
失败,因为它从{{1}开始}}。我们可以使用ftell
来说明这一点:
Ox: ...
当您切换fh = fopen('parameters', 'r');
fscanf(fh, 'YAcex: %f\n');
ftell(fh)
ans =
18 % The "O" is the 18th character in the file
和YOx:
行时,下一行的部分匹配不再发生,因此文件指针最终位于开头每次下一行,所有读取都成功。
那么,你怎么能解决这个问题呢?一种选择是始终指定size argument,以便KAce:
不会不必要地重新应用格式说明符:
fscanf
另一种选择是在一行中完成所有这些:
fh = fopen('parameters', 'r');
fscanf(fh, 'YAcex: %f\n', 1);
fscanf(fh, 'YOx: %f\n', 1);
fscanf(fh, 'KAce: %f\n', 1);
fclose(fh);
fh = fopen('parameters', 'r');
values = fscanf(fh, 'YAcex: %f\n YOx: %f\n KAce: %f\n');
fclose(fh);
将是一个3 x 1的数组,其中包含文件中的3个值。
答案 1 :(得分:1)
正如您已经意识到的那样,\ r或\ r \ n可能会导致此类行为。可能的原因与此类似,例如,某些地方有一些看不见的字符。你可以通过全部读取uint8来调试它,并查看出现问题的位置:
u8 = fread(fh, inf, '*uint8')';
避免此类问题的一种愚蠢方法是将all全部读为char,并搜索每个关键字:
fh = fopen('parameters');
ch = fread(fh, inf, '*char')'; % read all as char
fclose(fh);
YAcex = regexp(ch, '(?<=YAcex:\s?)[\d\.]+', 'match', 'once'); % parse YAcex
您可以相应地解析其他人。这样做的好处是它对某个地方的空间不太敏感,参数的顺序无关紧要。