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

28 visualizaciones (últimos 30 días)
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 comentarios
Maximilian Arpaio
Maximilian Arpaio el 16 de Abr. de 2018
(2) seems interesting. Any hint on the way to properly use the function within my script ?
per isakson
per isakson el 16 de Abr. de 2018
Editada: per isakson el 17 de Abr. de 2018
Sorry, I should have linked to: memmapfile, Create memory map to a file. memmap is over-kill.
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".

Iniciar sesión para comentar.

Respuestas (5)

Walter Roberson
Walter Roberson el 14 de Abr. de 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.

Maximilian Arpaio
Maximilian Arpaio el 15 de Abr. de 2018
Editada: Maximilian Arpaio el 15 de Abr. de 2018
Thanks to all for the different perspectives.
Actually, I still believe there is a means to do what I am trying to achieve. As an example, I've drafted the simple code below - that basically does what my script aims to do:
clearvars;
fid = fopen('testTriangle.txt','wt');
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: %4.2f m^2\n', areaT);
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);
%here the "fseek" or similar function should be placed, so as to move the
%cursor to line 5 and provide to the varialbe areaT the info calculated
%only in line 10.
fclose(fid);
Is the above example clarifying the matter ? I can either move the cursor to a specific line or according to a specific word, I'am quite flexible about this. I can also close the file and open it with a different fid if this helps.
Please advise !
  7 comentarios
Stephen23
Stephen23 el 15 de Abr. de 2018
Editada: Stephen23 el 17 de Abr. de 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.

Iniciar sesión para comentar.


dpb
dpb el 15 de Abr. de 2018
Editada: dpb el 15 de Abr. de 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 comentarios
dpb
dpb el 15 de Abr. de 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...
Maximilian Arpaio
Maximilian Arpaio el 16 de Abr. de 2018
Thanks dpb,
I've tried your code but the comment is added at the bottom of my (generated) file. My fault, but I forgot to highlight the fact that the script calls a "for" cycle and writes some values in the file. So when I place at the bottom of my file your code:
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);
text is place at the bottom, which is something that I don't want. Furthermore, this proves that I cannot rearrange this time....

Iniciar sesión para comentar.


Walter Roberson
Walter Roberson el 15 de Abr. de 2018
Editada: Walter Roberson el 16 de Abr. de 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.

Maximilian Arpaio
Maximilian Arpaio el 16 de Abr. de 2018
Thanks to all. I will go trough all the different advices and test your lines with my final code. As soon as I have a feedback, I will come back to you in the next hours. Cheers

Categorías

Más información sobre Low-Level File I/O en Help Center y File Exchange.

Etiquetas

Productos

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by