How can I move to a specific position in a txt file and write a value there? Target can be a specific word or bites from origin
31 views (last 30 days)
Show older comments
Hello, I've written a Matlab script that runs some calculation and that outputs the numerical/text results inside a txt file (generated on purpose) according to a specific layout (columns, comments, ...). The script works like a charm, but there is actually something more I would like to achieve: I need to write the result of a math operation in a specific position of the same txt file (which is close to the top/beginning of the txt file) but unfortunately that value to be written is calculated only at the bottom/end of the script. So the variable is not existing when the script should write it in the txt file (in the right position); it is calculated only later, once the script is over and I've reached the end of txt file.
I am thus looking for a function that can be placed at the end of my script code and that - once the script is over - moves the cursor from the bottom/top to a specific position of the txt file, gets a known value from my workspace of variables and writes it down in that specific position. The specific position can be either identified by a word or by 'X' bites from origin of file.
I was optmistic about "fseek", but either I am messing up or it is not the function I should use.
Please advise !
5 Comments
per isakson
on 16 Apr 2018
Edited: per isakson
on 17 Apr 2018
Hint:
ffs = 'c:\tmp\test.txt';
[fid,msg] = fopen( ffs, 'w' );
fprintf( fid, '%s', '1234567890----------1234567890' );
fclose( fid );
mmf = memmapfile( ffs, 'Writable',true );
reshape( mmf.Data, 1,[] )
mmf.Data(11:20) = uint8('abcdefghij');
clear('mmf')
type(ffs)
outputs
ans =
49 50 51 52 53 54 55 56 57 48 ...
1234567890abcdefghij1234567890
I'm a bit confused by the two bytes per character in Matlab vis-a-vis the one in the file. However, the above seems to work with "us-ascii".
Answers (5)
Walter Roberson
on 14 Apr 2018
You indicated that this is a text file. Formally speaking, there is no operation for seeking by offset in a text file. The only supported operation (other than beginning or end of file) is to ftell() to get a token representing the current position, after which you can fseek to the token to go back there.
fseek by absolute or relative position is only supported for binary files, not for text files.
The main difference between binary and text files is in the treatment of bytes that match the line terminator. Mostly this has to do with whether carriage return is dropped on input and automatically emitted on output when char(10) is output... Which can happen even for fwrite() if you are in text mode. But operating systems are permitted to do more complicated things in text mode. The specifications were written assuming that you might be writing a text file in the operating system of the WordStar devices that used to exist.
Still, using a text file it would be valid to open in w+ mode and to ftell() right before emitting the placeholder for the missing variable, and then later fseek back and fwrite exactly the same number of bytes as the placeholder making sure that you do emit any newlines when you do.
0 Comments
Maximilian Arpaio
on 15 Apr 2018
Edited: Maximilian Arpaio
on 15 Apr 2018
7 Comments
Stephen23
on 15 Apr 2018
Edited: Stephen23
on 17 Apr 2018
"how should I close this headache ?"
By avoiding it entirely. What you are trying to to is write hack code that messes around counting bytes written in files, something that is ugly and likely to fall apart when someone sneezes. However if you simply move all of the fprintf to the end of the script then this entire problem disappears. Calculate all values, then print to file. Why make it more complex than that?
"Even if I re-arrange the script, I would still face the fact the the comments must stay at the top of the file (like a kind of header) but the data only stay at the bottom. That's the reason why I see no other way in my script that to leave it as it is..."
The order of calculation is totally unrelated to the order that that data can be printed to file. MATLAB does not restrict you to printing the data in the same order that it is created. Create some values, do some calculations, store the values in variables. Print them all when you are finished, in whatever order you wish. No hacking around with file byte counting is required.
dpb
on 15 Apr 2018
Edited: dpb
on 15 Apr 2018
>> maxim
>> type testTriangle.txt
#THIS IS MY SCRIPT
#IT CALCULATES THE PERIMETER OF A TRIANGLE OF AREA: 18.81 m^2
#THE PERIMETER OF THE TRIANGLE IS: 18.90 m
>>
>> type maxim
% compute what is wanted/needed...
A=5.3;
B=6.5;
C=7.1;
Perimeter=A+B+C;
areaT=A*C/2;
% NOW write out the results in the desired order
fid = fopen('testTriangle.txt','wt');
fprintf(fid,'#THIS IS MY SCRIPT\n');
fprintf(fid,'#IT CALCULATES THE PERIMETER OF A TRIANGLE OF AREA: %4.2f m^2\n', areaT);
fprintf(fid,'#THE PERIMETER OF THE TRIANGLE IS: %4.2f m\n', Perimeter);
fclose(fid);
>>
Simply rearrange when you do things; wait until it's time; and time is when you have the results required to do the task.
NB:
If the "extended calculations" are indeed of tremendous size and create a huge file and there really is some nontrivial reason can't wait to write earlier results before some final answer drops out at the bottom, the more efficient way to do so is to write that portion of the file independently of the header and when the header information is ready, write a separate header file containing that information that belongs therein.
Then, as the last operation before quitting the script, one simply copies the larger calculations file onto the tail of the header file; iow the two files are combined together to create the final file. This is done most simply by just passing the appropriate command to the operating system.
2 Comments
dpb
on 15 Apr 2018
It's almost certainly the most wrongheaded way to possibly solve the problem, but...
...
fid = fopen('testTriangle.txt','w');
n=fprintf(fid,'#THIS IS MY SCRIPT\n');
n=n+fprintf(fid,'#IT CALCULATES THE PERIMETER OF A TRIANGLE OF AREA: ');
fprintf(fid,'%4.2f m^2\n', 99.99);
fprintf(fid,'#THE PERIMETER OF THE TRIANGLE IS: %4.2f m\n', Perimeter);
% Absolutely wrongheaded, but...
fseek(fid,n,'bof');
fprintf(fid,'%4.2f',areaT);
fclose(fid);
will overwrite the '99.99' placeholder value; all the preceding issues exist in trying to make this work in general, but, yes, you can write on top of a sequential file at any point within it but it is terribly fraught with "there be dragons!" and as the opening comment says...
Walter Roberson
on 15 Apr 2018
Edited: Walter Roberson
on 16 Apr 2018
width_for_placeholder = 20;
fid = fopen('testTriangle.txt','w+t'); %notice change
fprintf(fid,'#THIS IS MY SCRIPT\n');
fprintf(fid,'#IT CALCULATES THE PERIMETER OF A TRIANGLE \n\n');
fprintf(fid,'#THAT HAS AN AREA OF: '); % I want to place here the value of the variable
cursor = ftell(fid);
fwrite(fid, uint8(blanks(width_for_placeholder))); %reserved for "areaT"
fprintf(fid, '\n');
A=5.3;
B=6.5;
C=7.1;
Perimeter=A+B+C;
areaT=A*C/2;
fprintf(fid,'#THE PERIMETER OF THE TRIANGLE IS: %4.2f m\n', Perimeter);
fseek(fid, cursor, 'bof');
fmt_areat = uint8( sprintf('%*.10g', width_for_placeholder, areaT) ); %g format is good about respecting widths no matter what the range of values
%it is important that the output be exactly the reserved length!
if length(fmt_areat) ~= width_for_placeholder
fmt_areat = repmat(uint8('*'), 1, width_for_placeholder);
fprintf('Warning: area value overflowed available width, replaced with **');
end
fwrite(fid, fmt_areat);
%do NOT output a newline here!!
fclose(fid);
The uint8() part is so that we are reserving an exact number of bytes no matter what the character encoding.
Note: if the character encoding is UTF-16 then the area will not be written out in UTF-16. It would be possible to do so, by adding a couple of extra lines.
0 Comments
Maximilian Arpaio
on 16 Apr 2018
2 Comments
Walter Roberson
on 16 May 2019
We gave precise code. After, that is, plenty of warnings as to why this should be avoided.
See Also
Categories
Find more on Low-Level File I/O in Help Center and File Exchange
Products
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!