I am trying to read the information contained in a small configuration file with Matlab's fscanf function. The content of the file is;
YAcex: 1.000000
YOx: 1.000000
KAce: 1.000000
The matlab code used to parse the file is;
fh = fopen('parameters', 'r');
fscanf(fh, 'YAcex: %f\n')
fscanf(fh, 'YOx: %f\n')
fscanf(fh, 'KAce: %f\n')
fclose(fh);
When this script is invoked, only the "YAcex" line is read correctly; fscanf returns []
for the two other lines. If the YOx and KAce lines are switched (KAce before YOx), all lines are read correctly by fscanf.
Can someone explain this behavior?
supplementary information: The linefeeds in the input file are simple linefeed (\n character, without \r character).
Your problem is that you only want to read one value per call to fscanf
, but by default it tries to read as many values as possible. Note this excerpt from the documentation:
The
fscanf
function reapplies the format throughout the entire file and positions the file pointer at the end-of-file marker. Iffscanf
cannot matchformatSpec
to the data, it reads only the portion that matches and stops processing.
This means the first call correctly reads the first line of the file, but then tries to read the next line as well, finding no exact match to its format specifier. It finds a partial match for the next line, where the first Y
of YOx:
matches the beginning of YAcex:
in the format specifier. This partial match places the file pointer directly after the Y
in YOx:
, causing the next call to fscanf
to fail since it is starting at the Ox: ...
. We can illustrate this with ftell
:
fh = fopen('parameters', 'r');
fscanf(fh, 'YAcex: %f\n');
ftell(fh)
ans =
18 % The "O" is the 18th character in the file
When you switch the YOx:
and KAce:
lines, a partial match of the next line doesn't happen any more, so the file pointer ends up at the beginning of the next line every time and all the reads are successful.
So, how can you get around this? One option is to always specify the size argument so fscanf
doesn't reapply the format specifier unnecessarily:
fh = fopen('parameters', 'r');
fscanf(fh, 'YAcex: %f\n', 1);
fscanf(fh, 'YOx: %f\n', 1);
fscanf(fh, 'KAce: %f\n', 1);
fclose(fh);
Another option is to do this all in one line:
fh = fopen('parameters', 'r');
values = fscanf(fh, 'YAcex: %f\n YOx: %f\n KAce: %f\n');
fclose(fh);
And values
will be a 3-by-1 array containing the 3 values from the file.
As you already realized, \r or \r\n could cause this kind of behavior. The likely reason is similar to that, for example, there is some invisible characters like space somewhere. You can debug this by reading all as uint8, and take a look at the location where problem occurs:
u8 = fread(fh, inf, '*uint8')';
One stupid way to avoid this kind of issue is to read all as char, and search each keyword:
fh = fopen('parameters');
ch = fread(fh, inf, '*char')'; % read all as char
fclose(fh);
YAcex = regexp(ch, '(?<=YAcex:\s?)[\d\.]+', 'match', 'once'); % parse YAcex
You can parse others accordingly. The advantage of this is that it is less sensitive to a space somewhere, and the order of parameters does not matter.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With