Truncate a file: Difference between revisions

→‎{{header|Fortran}}: I wonder how general this would be...
(→‎{{header|Go}}: Add Fortran.)
(→‎{{header|Fortran}}: I wonder how general this would be...)
Line 426:
So, plan B is to copy the desired part of the file to a temporary storage area then write it back out again. Standard Fortran has no access to facilities that might change a disc file's name, though it can delete one via <code>CLOSE(F, STATUS = "DELETE")</code> - unless it had been opened with READONLY. It can however overwrite a file, or more precisely, close the file then reopen it with STATUS="REPLACE". This is rather bad, because there will be a period during which the desired data in the file might vanish, due to a power failure or system crash (or running out of disc space, or...) before the rewriting has been completed which is why the source file should be renamed to something, the new version written, and only then (if at all), the original deleted. This imposes a greater requirement on storage space, but avoids a catastrophic loss of data. By going for the input file with ACTION="READWRITE" even though it will only be read from, there is a chance of an early rebuff if write authority is not available as will be needed when it is reopened with STATUS="REPLACE" - though there is a brief opportunity for trouble after the close and before the reopen.
 
The details turn out to be tricky. There is no equivalent of Turbo Pascal's BlockRead(F,stuff,size(stuff),N) whereby the next block of bytes from file F are read (or, similarly, written) up to the size of the recipient "stuff", with the number actually read appearing in N as when the amount remaining is smaller than "stuff". It is possible to use the Q-format feature (not standard, but common) that states how many characters are yet to be read from an input record, however, this is for FORM="FORMATTED", and in the ASCII world, the record dividers are indicated in-line by one of CR, CRLF, LFCR, or LF which are ''not'' counted in the character count, nor can they be imputed as being present because you don't know which length is being used and even if the code investigates to find out, I have seen a mixture in the one file. The task evidently means for the byte count to be absolute, not omitting the space occupied by such splitters if present. A file containing binary data rather than text (though both are bits, no more, no less), say integers and floating-point numbers, etc. will likely have bytes containing a CR or LF here and there just by chance, but if on output they are reconstituted as CRLF (or whichever is used) the resulting file will be uselessly damaged.
 
Accordingly, the input must be read in the UNFORMATTED style. This is done with a specified record length, but again unlike the BlockRead procedure there is no indication of a short record at the end - if the record length is say 60, there is no guarantee that the file's length will be a multiple of sixty and the remainder will cause trouble. The ERR=''label'' can catch this mishap, but still, there is no indication of by how much the remaining portion of the file fell short. The only record length that will divide all possible file lengths is ... one. Now arises a minor obstacle: some systems use the size of a default INTEGER to be the unit of a RECL=''n'', but fortunately, a compiler option allows the specification of the record length to be in units of bytes.
 
Initial tests threw up further obstacles, such as "end-of-file during read", the very first read. Floundering discovered that escalating to random access avoided this confusion, so ACCESS="DIRECT" and READ (F,REC=L) worked, except that the END action label is not permitted for direct access. ERR instead, to cover the case when a byte beyond end-of-file is requested, clearly an error.
Despite writing output as a single byte at a time, the output file appeared to manifest as a file having records with a 32-bit record length of value one (not helped by endian issues) followed by the content, but changing to writing each byte of the output using the FORM="FORMATTED" option dodged that, provided that each output employed the "$" output format code that signifies that a record ender (the CR, etc. mess) is not to be appended. After these experiences, one suspects that each system will have its own quirks for some types of file, and testing will be required.
 
There is an option to specify BUFFERED="YES" and BUFFERCOUNT=n or similar in many Fortrans, but alas, these are not standard even in F90/95. One's guilt is not so easily diverted, but, ... this is really only a demonstration, perhaps with very occasional use.
1,220

edits