Truncate a file: Difference between revisions

→‎{{header|Go}}: Add Fortran.
No edit summary
(→‎{{header|Go}}: Add Fortran.)
Line 420:
}</lang>
Package os also has a separate function that operates on an open file.
 
=={{header|Fortran}}==
Fortran offers no access to any facilities the file system may offer for truncating a disc file via standard language features, thus in the absence of special routines or deviant compilers that do, you're stuck.
 
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.
 
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. 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.
 
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.
 
And so...<lang Fortran> SUBROUTINE CROAK(GASP) !Something bad has happened.
CHARACTER*(*) GASP !As noted.
WRITE (6,*) "Oh dear. ",GASP !So, gasp away.
STOP "++ungood." !Farewell, cruel world.
END !No return from this.
 
SUBROUTINE FILEHACK(FNAME,NB)
CHARACTER*(*) FNAME !Name for the file.
INTEGER NB !Number of bytes to survive.
INTEGER L !A counter for te length of the file.
INTEGER F,T !Mnemonics for file unit numbers.
PARAMETER (F=66,T=67) !These should do.
LOGICAL EXIST !Same as the mnemonic so left/right can be forgotten.
CHARACTER*1 B !The worker!
IF (FNAME.EQ."") CALL CROAK("Blank file name!")
IF (NB.LE.0) CALL CROAK("Chop must be positive!")
INQUIRE(FILE = FNAME, EXIST = EXIST) !This mishap is frequent, so attend to it.
IF (.NOT.EXIST) CALL CROAK("Can't find a file called "//FNAME) !Tough love.
OPEN (F,FILE=FNAME,STATUS="OLD",ACTION="READWRITE", !Grab the source file.
1 FORM="UNFORMATTED",RECL=1,ACCESS="DIRECT") !Oh dear.
OPEN (T,STATUS="SCRATCH",FORM="UNFORMATTED",RECL=1) !Request a temporary file.
 
Copy the desired "records" to the temporary file.
10 DO L = 1,NB !Only up to a point.
READ (F,REC = L,ERR = 20) B !One whole byte!
WRITE (T) B !And, write it too!
END DO !Again.
20 IF (L.LE.NB) CALL CROAK("Short file!") !Should end the loop with L = NB + 1.
Convert from input to output...
REWIND T !Not CLOSE! That would discard the file!
CLOSE(F) !The source file still exists.
OPEN (F,FILE=FNAME,FORM="FORMATTED", !But,
1 ACTION="WRITE",STATUS="REPLACE") !This dooms it!
Copy from the temporary file.
DO L = 1,NB !A certain number only.
READ (T) B !One at at timne.
WRITE (F,"(A1,$)") B !The $, obviously, means no end-of-record appendage.
END DO !And again.
Completed.
30 CLOSE(T) !Abandon the temporary file.
CLOSE(F) !Finished with the source file.
END !Done.
 
PROGRAM CHOPPER
CALL FILEHACK("foobar.txt",12)
END</lang>
 
=={{header|Haskell}}==
1,220

edits