fscanf函数的奇怪行为

时间:2017-08-21 12:33:21

标签: matlab scanf

我试图用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字符)。

2 个答案:

答案 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 

您可以相应地解析其他人。这样做的好处是它对某个地方的空间不太敏感,参数的顺序无关紧要。