From maintainers-request at octave dot org Fri Jan 27 23:39:08 2006 Subject: Is there a better way to fwrite()? From: Daniel J Sebald To: octave maintainers mailing list Date: Fri, 27 Jan 2006 23:46:17 -0600 I'm going to lobby a bit here for a change of behavior in "fwrite", illustrated by the following example: Say I want to write to a binary file tuples of numbers, oh 10 unit8's and 2 float32's. I want to do this efficiently, rather than using some kind of loop. Well, let's think of how to do that with fwrite(). One's inclination would be to use skip and multiple applications of fwrite in some way. Try this: fid = fopen('test.bin', 'w+'); X = [ones(10); rand(2,10)]; here = ftell(fid); fseek(fid, here, 'bof'); fwrite(fid, X(1:10,:), '10*uint8', 8); fclose(fid); as just a means to get started. Similar to fread, one might think, hey this will write 10 uint8's then skip the space for the two float32's. However, we see that "there is nothing to skip" because there isn't yet any data at the end of the file to skip. So this actually turns out to be only 100 bytes. [use hexedit to observe the file.] I argue that it would be nice for fwrite() to place some bytes of 0 in there, but I'll come back to that. I don't show the remaining commands for writing the two float32's. It obviously won't work. Let's move on. OK, how about this: fid = fopen('test.bin', 'w+'); X = [ones(10); rand(2,10)]; here = ftell(fid); fwrite(fid, zeros(18,10), 'char'); fseek(fid, here - 8, 'bof'); fwrite(fid, X(1:10,:), '10*uint8', 8); fseek(fid, here, 'bof'); fwrite(fid, X(11:12,:), '2*float32', 10); fclose(fid); The "here - 8" is because fwrite() "pre-skips" as opposed to "post-skips" as does fread(). Slightly confusing, but workable, accept for one thing in this case. If here equals 0, here - 8 seems to be undefined as far as a file pointer. If one looks at the results using hexedit, the 1's appear way at the end of the file. But the thing to note here is the inconvenient write of an equal amount of zeros first. It's like writing the data twice. And here is the final correct code that gets what I want: fid = fopen('test.bin', 'w+'); X = [ones(10); rand(2,10)]; here = ftell(fid); fwrite(fid, zeros(18,10), 'char'); fseek(fid, here, 'bof'); fwrite(fid, X(1:10,1), '10*uint8'); fwrite(fid, X(1:10,2:10), '10*uint8', 8); fseek(fid, here, 'bof'); fwrite(fid, X(11:12,:), '2*float32', 10); fclose(fid); So, questions: 1) Why can't a negative number be a valid file pointer so that the pre-skip of fwrite() would work correctly with fid = fopen('test.bin', 'w+'); X = [ones(10); rand(2,10)]; here = ftell(fid); fwrite(fid, zeros(18,10), 'char'); fseek(fid, here - 8, 'bof'); fwrite(fid, X(1:10,:), '10*uint8', 8); fseek(fid, here, 'bof'); fwrite(fid, X(11:12,:), '2*float32', 10); fclose(fid); and avoid an extra command? 2) Why can't fwrite() put zeros in place of the "skipped" bytes at the end of the file if they do not exist? That way I could use fid = fopen('test.bin', 'w+'); X = [ones(10); rand(2,10)]; here = ftell(fid); fseek(fid, here - 8, 'bof'); fwrite(fid, X(1:10,:), '10*uint8', 8); fseek(fid, here, 'bof'); fwrite(fid, X(11:12,:), '2*float32', 10); fclose(fid); and avoid having to write the same amount of data twice. I understand the logic why not--there is nothing at the end of the file to skip. But as it is right now with a file empty at the end, the following are essentially the same: fwrite(fid, X(1:10,:), '10*uint8', 8); fwrite(fid, X(1:10,:), '10*uint8'); Surely, one wouldn't expect those to have the same behavior. I.e., no one would choose the first in the expectation that it will behave like the second, whould they? Dan PS: fwrite(fid, X, '10*uint8,2*float32') would be the nicest solution, but that doesn't seem to work and probably isn't the way things are defined.