Truncate a file: Difference between revisions
→{{header|Fortran}}
m (→{{header|REXX}}: changed a version name (title).) |
|||
(53 intermediate revisions by 30 users not shown) | |||
Line 1:
{{task}}
[[Category:File System Operations]]
;Task:
Truncate a file to a specific length. This should be implemented as a routine that takes two parameters: the filename and the required file length (in bytes).
Truncation can be achieved using system or library calls intended for such a task, if such methods exist, or by creating a temporary file of a reduced size and renaming it, after first deleting the original file, if no other method is available. The file may contain non human readable binary data in an unspecified format, so the routine should be "binary safe", leaving the contents of the untruncated part of the file unchanged.
If the specified filename does not exist, or the provided length is not less than the current file length, then the routine should raise an appropriate error condition.
On some systems, the provided file truncation facilities might not change the file or may extend the file, if the specified length is greater than the current length of the file.
This task permits the use of such facilities. However, such behaviour should be noted, or optionally a warning message relating to an non change or increase in file size may be implemented.
<br><br>
=={{header|11l}}==
{{trans|Python}}
<syntaxhighlight lang="11l">F truncate_file(name, length)
I !fs:is_file(name)
R 0B
I length >= fs:file_size(name)
R 0B
fs:resize_file(name, length)
R 1B</syntaxhighlight>
=={{header|Action!}}==
The attached result has been obtained under DOS 2.5.
{{libheader|Action! Tool Kit}}
<syntaxhighlight lang="action!">INCLUDE "D2:IO.ACT" ;from the Action! Tool Kit
PROC Dir(CHAR ARRAY filter)
BYTE dev=[1]
CHAR ARRAY line(255)
Close(dev)
Open(dev,filter,6)
DO
InputSD(dev,line)
PrintE(line)
IF line(0)=0 THEN
EXIT
FI
OD
Close(dev)
RETURN
BYTE FUNC Find(CHAR ARRAY text CHAR c)
BYTE i
i=1
WHILE i<=text(0)
DO
IF text(i)=c THEN
RETURN (i)
FI
i==+1
OD
RETURN (0)
PROC MakeRenameCommand(CHAR ARRAY left,right,result)
BYTE i,len,pos
SCopy(result,left)
len=left(0)+1
result(len)=32
pos=Find(right,':)
FOR i=pos+1 TO right(0)
DO
len==+1
result(len)=right(i)
OD
result(0)=len
RETURN
PROC DeleteFile(CHAR ARRAY fname)
BYTE dev=[1]
Close(dev)
Xio(dev,0,33,0,0,fname)
RETURN
PROC TruncateFile(CHAR ARRAY fname CARD maxlen)
DEFINE BUF_LEN="100"
CHAR ARRAY tmp="D:TEMP.TMP",cmd(255)
BYTE in=[1], out=[2]
BYTE ARRAY buff(BUF_LEN)
CARD len,size
Close(in)
Close(out)
Open(in,fname,4)
Open(out,tmp,8)
DO
IF maxlen>BUF_LEN THEN
size=BUF_LEN
ELSE
size=maxlen
FI
len=Bget(in,buff,size)
maxlen==-len
IF len>0 THEN
Bput(out,buff,len)
FI
UNTIL len#BUF_LEN
OD
Close(in)
Close(out)
MakeRenameCommand(tmp,fname,cmd)
DeleteFile(fname)
Rename(cmd)
RETURN
PROC Main()
CHAR ARRAY filter="D:*.*", fname="D:INPUT.TXT"
CARD len=[400]
Put(125) PutE() ;clear screen
PrintF("Dir ""%S""%E",filter)
Dir(filter)
PrintF("Truncate ""%S"" to %U bytes.%E%E",fname,len)
TruncateFile(fname,len)
PrintF("Dir ""%S""%E",filter)
Dir(filter)
RETURN</syntaxhighlight>
{{out}}
[https://gitlab.com/amarok8bit/action-rosetta-code/-/raw/master/images/Truncate_a_file.png Screenshot from Atari 8-bit computer]
<pre>
Dir "D:*.*"
DOS SYS 037
DUP SYS 042
INPUT TXT 037
591 FREE SECTORS
Truncate "D:INPUT.TXT" to 400 bytes.
Dir "D:*.*"
DOS SYS 037
DUP SYS 042
INPUT TXT 004
624 FREE SECTORS
</pre>
=={{header|Ada}}==
Line 11 ⟶ 153:
The following program is an implementation in Ada using system-independent tools from the standard library to read and write files, remove and rename them. It should work for on any system with byte-oriented file storage and uses Ada 2012 conditional expressions.
<
procedure Truncate_File is
Line 65 ⟶ 207:
end if;
end;
end Truncate_File;</
=={{header|AutoHotkey}}==
<
return
Line 80 ⟶ 222:
f.length := length_bytes
f.close()
}</
=={{header|AWK}}==
<syntaxhighlight lang="awk">
# syntax: GAWK -f TRUNCATE_A_FILE.AWK
BEGIN {
main("NOTHERE",100)
main("FILENAME.TMP",-1)
main("FILENAME.TMP",500)
exit(0)
}
function main(filename,size, ret) {
ret = truncate_file(filename,size)
if (ret != "") {
printf("error: FILENAME=%s, %s\n",filename,ret)
}
}
function truncate_file(filename,size, cmd,fnr,msg,old_BINMODE,old_RS,rec) {
cmd = sprintf("ls --full-time -o %s",filename)
if (size < 0) {
return("size cannot be negative")
}
old_BINMODE = BINMODE
old_RS = RS
BINMODE = 3
RS = "[^\x00-\xFF]"
while (getline rec <filename > 0) {
fnr++
}
close(filename)
if (fnr == 0) {
msg = "file not found"
}
if (fnr > 1) {
msg = "choose a different RecordSeparator"
}
if (msg == "") { # no errors
system(cmd) # optional: show filesize before truncation
if (length(rec) > size) {
rec = substr(rec,1,size)
}
printf("%s",rec) >filename
close(filename)
system(cmd) # optional: show filesize after truncation
}
BINMODE = old_BINMODE
RS = old_RS
return(msg)
}
</syntaxhighlight>
{{out}}
<pre>
error: FILENAME=NOTHERE, file not found
error: FILENAME=FILENAME.TMP, size cannot be negative
-rw-r--r-- 1 1001 240128 Mon Aug 02 12:18:15 2004 FILENAME.TMP
-rw-r--r-- 1 1001 500 Sat Jan 07 00:55:28 2017 FILENAME.TMP
</pre>
=={{header|BASIC}}==
Line 87 ⟶ 285:
This is fairly generic MS BASIC. As such, it actually works in a wide variety of compilers and interpreters -- certainly too many to list here, but the list includes non-.Net [[Visual Basic]], [[FreeBASIC]], [[QB64]], etc. With a user-provided implementation of <code>DIR$</code>, it even works under [[QBasic]].
<
IF LEN(DIR$(file)) THEN
DIM f AS LONG, c AS STRING
Line 106 ⟶ 304:
ERROR 53
END IF
END SUB</
See also: [[#FreeBASIC|FreeBASIC]], [[#Liberty BASIC|Liberty BASIC]], [[#PowerBASIC|PowerBASIC]], [[#PureBasic|PureBasic]], [[#ZX Spectrum Basic|ZX Spectrum Basic]].
=={{header|BBC BASIC}}==
This will extend the file if the specified length is greater than the existing length. A test to prevent that could easily be added.
<
LOCAL file%
file% = OPENUP(file$)
Line 118 ⟶ 316:
EXT#file% = size%
CLOSE #file%
ENDPROC</
=={{header|Bracmat}}==
Handling binary data is not easy in Bracmat. This solution reads all bytes as numbers. They are prepended to a list. After reversing the list, all numbers are written to the file. Notice that to close a file you should try to seek to a non-existing file position.<code>fil$(,SET,-1)</code> seeks to the position before the start of the file currently in focus.
<
= name length elif file c
. !arg:(?name,?length)
Line 144 ⟶ 342:
| out$"File too short"
)
);</
Output:
<pre>I have a secret to t</pre>
Line 157 ⟶ 355:
{{works with|MinGW}}
<
#include <stdio.h>
#include <wchar.h>
Line 237 ⟶ 435:
return dotruncate(fn, fp);
}</
===POSIX===
<
#include <sys/types.h>
Line 247 ⟶ 445:
ftruncate(fd, length);
...
</syntaxhighlight>
Both functions have <code>length</code> argument of <code>off_t</code> type. There are about a million possible errors, of interest to this task are <code>EFBIG</code>: size too large; <code>EINVAL</code>: size is negative or too large; <code>EIO</code>: IO error; <code>EACCESS</code> (for <code>truncate</code>): either can't see or can't write to the file; <code>EBADF</code> or <code>EINVAL</code> (for <code>ftruncate</code>): file descriptor is not a file descriptor, or not opened for writing.
Line 254 ⟶ 452:
=={{header|C sharp}}==
<
using System.IO;
Line 281 ⟶ 479:
}
}
}</
=={{header|C++}}==
<syntaxhighlight lang="c++">#include <string>
#include <fstream>
using namespace std;
void truncateFile(string filename, int max_size) {
std::ifstream input( filename, std::ios::binary );
char buffer;
string outfile = filename + ".trunc";
ofstream appendFile(outfile, ios_base::out);
for(int i=0; i<max_size; i++) {
input.read( &buffer, sizeof(buffer) );
appendFile.write(&buffer,1);
}
appendFile.close(); }
int main () {
truncateFile("test.txt", 5);
return 0;
}
</syntaxhighlight>
=={{header|Clojure}}==
{{trans|Java}}
<syntaxhighlight lang="clojure">(defn truncate [file size]
(with-open [chan (.getChannel (java.io.FileOutputStream. file true))]
(.truncate chan size)))
(truncate "truncate_test.txt" 2)</syntaxhighlight>
=={{header|D}}==
<
void truncateFile(in string name, in size_t newSize) {
Line 305 ⟶ 534:
void main() {
truncateFile("truncate_test.txt", 0);
}</
=={{header|Delphi}}==
Line 311 ⟶ 540:
Delphi has the same <code>truncate</code> method as Pascal, which could be used like this:
<
var
aFile: file of byte;
Line 323 ⟶ 552:
Close(afile);
end;
end;</
Most people nowadays seem to use streams to access files, so an alternative is:
<
var
Stream : TFileStream;
Line 337 ⟶ 566:
Stream.Free;
end;
end;</
With both of these approaches, if the NewSize is greater than the existing file size the file will be expanded and filled with nulls.
Line 347 ⟶ 576:
If you try to truncate a non-existent file using a stream you will get an EFOpenError exception with the message:
Cannot open file "<File name with full path>. The system cannot find the file specified.
=={{header|Elena}}==
ELENA 6.x:
<syntaxhighlight lang="elena">import system'io;
import extensions;
extension fileOp : File
{
set Length(int len)
{
auto stream := FileStream.openForEdit(self);
stream.Length := len;
stream.close()
}
}
public program()
{
if (program_arguments.Length != 3)
{ console.printLine("Please provide the path to the file and a new length"); AbortException.raise() };
auto file := File.assign(program_arguments[1]);
var length := program_arguments[2].toInt();
ifnot(file.Available)
{ console.printLine("File ",file," does not exist"); AbortException.raise() };
file.Length := length
}</syntaxhighlight>
=={{header|Erlang}}==
<syntaxhighlight lang="erlang">
-module( truncate ).
Line 361 ⟶ 621:
{ok, Size} = file:position( IO, {bof, Size} ),
ok = file:truncate( IO ).
</syntaxhighlight>
=={{header|F_Sharp|F#}}==
{{trans|C#}}
<
open System.IO
Line 377 ⟶ 637:
let main args =
truncateFile args.[0] (Int64.Parse(args.[1]))
0</
=={{header|Forth}}==
<syntaxhighlight lang="forth">
: truncate-file ( fname fnamelen fsize -- )
0 2swap r/w open-file throw
dup >r resize-file throw
r> close-file throw ;
</syntaxhighlight>
=={{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. 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.
And so...<syntaxhighlight 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</syntaxhighlight>
=={{header|FreeBASIC}}==
{{trans|QuickBASIC}}
<syntaxhighlight lang="freebasic">Sub truncateFile (archivo As String, longitud As Long)
If Len(Dir(archivo)) Then
Dim f As Long, c As String
f = Freefile
Open archivo For Binary As #f
If longitud > Lof(f) Then
Close #f
Error 62 'Input past end of file
Else
c = Space(longitud)
Get #f, 1, c
Close f
Open archivo For Output As #f
Print #f, c;
Close #f
End If
Else
Error 53 'File not found
End If
End Sub</syntaxhighlight>
=={{header|Go}}==
Go has the required function in the standard library. The implementation calls operating system specific functions and returns whatever errors the operating system reports.
<
"fmt"
"os"
Line 388 ⟶ 739:
if err := os.Truncate("filename", newSize); err != nil {
fmt.Println(err)
}</
Package os also has a separate function that operates on an open file.
Line 394 ⟶ 745:
This can be achieved by using the <code>setFileSize</code> function in [http://hackage.haskell.org/packages/archive/unix-compat/0.1.2.1/doc/html/System-PosixCompat-Files.html#13 System.PosixCompat.Files]:
<
-- Truncates the file down to the specified length.
-- If the file was larger than the given length
-- before this operation was performed the extra is lost.
-- Note: calls truncate.
</syntaxhighlight>
=={{header|Icon}} and {{header|Unicon}}==
Unicon provides the built-in function truncate which can be used to truncate a file. The following line of code truncates ''filename'' to ''newsizeinbytes''. The file is opened for both read and write in untranslated mode.
<
Note: The Unicon book incorrectly indicates that truncate doesn't work on Windows.
=={{header|J}}==
'''Solution:'''
<
ftruncate=: ] fwrite~ ] fread@; 0 , [</
'''Usage:'''
<
567 ftruncate 'test.txt' NB. truncate test file
567
fsize 'test.txt' NB. check new file size
567</
=={{header|Java}}==
The built-in function for truncating a file in Java will leave the file unchanged if the specified size is larger than the file. This version expects the source file name and the new size as command line arguments (in that order).
<
import java.io.IOException;
import java.nio.channels.FileChannel;
Line 435 ⟶ 786:
outChan.close();
}
}</
=={{header|jq}}==
jq cannot itself perform the specified task
because it cannot "truncate a file" in the sense of the question.
In particular, it is not "binary safe", and cannot itself write to files named on the command line.
Another issue is that jq can only read UTF-8-encoded files, and generally speaking is oriented
to codepoints rather than bytes.
So for this task, we'll assume that `sponge` is available for overwriting a file,
and that the "size" is specified in codepoints rather than bytes.
<pre>
< input.txt jq -Rr --argjson size $size '
if length < $size then "file size is less than the specified size" | error
else .[:$size]
end
' | sponge input.txt
</pre>
=={{header|Julia}}==
Uses the built-in <code>truncate</code> function (which truncates a stream):
<
open(fname, "r+") do f
truncate(f, size)
end
end</
=={{header|Kotlin}}==
<syntaxhighlight lang="scala">// version 1.1.2
import java.io.FileOutputStream
import java.nio.channels.FileChannel
fun truncateFile(fileName: String, newSize: Long) {
var fc: FileChannel? = null
try {
fc = FileOutputStream(fileName, true).channel
if (newSize >= fc.size())
println("Requested file size isn't less than existing size")
else
fc.truncate(newSize)
}
catch (ex: Exception) {
println(ex.message)
}
finally {
fc!!.close()
}
}
fun main(args: Array<String>) {
truncateFile("test.txt", 10)
}</syntaxhighlight>
=={{header|Lasso}}==
<
local(file = file(#path))
Line 464 ⟶ 862:
stdoutnl(file(#filepath) -> readbytes)
stdout(file('Truncated size: ' + #filepath) -> size)</
Output:
<pre>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris consequat
Line 487 ⟶ 885:
<br>
It is also possible to call API functions to achieve this task.
<syntaxhighlight lang="lb">
dim info$( 50, 50) ' NB pre-dimension before calling file-exists
' needed for file-exists function
Line 518 ⟶ 916:
end
</syntaxhighlight>
=={{header|
With native means (Fileio Xtra) file truncation can only be implemented indirectly, either using a temp file or loading truncated file contents into memory, deleting original and writing memory back to file:
<syntaxhighlight lang="lingo">----------------------------------------
-- Truncates file
-- @param {string} filename
-- @param {integer} length
-- @return {bool} success
----------------------------------------
on truncate (filename, length)
fp = xtra("fileIO").new()
fp.openFile(filename, 0)
if fp.status() then return false
if fp.getLength()=length then
-- nothing to do
fp.closeFile()
return true
end if
data = fp.readByteArray(length)
if data.length<>length then
fp.closeFile()
return false
end if
fp.delete()
fp.createFile(filename)
fp.openFile(filename, 2)
fp.writeByteArray(data)
ok = fp.status()=0
fp.closeFile()
return ok
end</syntaxhighlight>
But there are also free plugins ("Xtras") like e.g. "BinFile Xtra" that support "in-file" truncation:
{{libheader|BinFile Xtra}}
<syntaxhighlight lang="lingo">-- truncates file to 10 KB length
bx_file_truncate(_movie.path&"foo.dat", 10240)</syntaxhighlight>
=={{header|Lua}}==
Lua treats strings as being invariably one byte per character (hence the awkwardness of trying to use it with unicode), so it's safe to use string methods to truncate binary data.
<syntaxhighlight lang="lua">function truncate (filename, length)
local inFile = io.open(filename, 'r')
if not inFile then
error("Specified filename does not exist")
end
local wholeFile = inFile:read("*all")
inFile:close()
if length >= wholeFile:len() then
error("Provided length is not less than current file length")
end
local outFile = io.open(filename, 'w')
outFile:write(wholeFile:sub(1, length))
outFile:close()
end</syntaxhighlight>
=={{header|Mathematica}}/{{header|Wolfram Language}}==
<syntaxhighlight lang="mathematica">Truncate[file_, n_] := Module[{filename = file, nbbytes = n, temp},
temp = $TemporaryPrefix <> filename;
BinaryWrite[temp, BinaryReadList[filename, "Byte", nbbytes]];
Close[temp]; DeleteFile[filename]; RenameFile[temp, filename];
]</
=={{header|MATLAB}} / {{header|Octave}}==
<
fid=fopen(fn,'r');
Line 536 ⟶ 986:
fid=fopen(fn,'w');
s = fwrite(fid,s,'uint8');
fclose(fid); </
=={{header|Nim}}==
Nim provides the module "posix" which allows to use the Posix functions in Nim programs. The behavior is that of the "truncate" Posix function. Especially, if the provided length is greater than the current file size, the file is expanded at the requested length with null bytes.
The function returns a code which can be checked to emit a message or raise an exception in case of error. In the following example, we ignore (discard) this return code.
<syntaxhighlight lang="nim">import posix
discard truncate("filename", 1024)</syntaxhighlight>
=={{header|OCaml}}==
Line 547 ⟶ 1,001:
The <code>Unix</code> module provided with the standard distribution provides a function <code>[http://caml.inria.fr/pub/docs/manual-ocaml/libref/Unix.html#VALtruncate truncate]</code>:
<
(** Truncates the named file to the given size. *)</
There is also a function <code>[http://caml.inria.fr/pub/docs/manual-ocaml/libref/Unix.html#VALftruncate ftruncate]</code> that does the equivalent operation but with a file descriptor instead of a file name:
<
(** Truncates the file corresponding to the given descriptor to the given size. *)</
=={{header|PARI/GP}}==
Create a file /tmp/test.file and truncate to 20 bytes: (Linux only)
<syntaxhighlight lang="parigp">install("truncate", "isL", "trunc")
trunc("/tmp/test.file", 20)</syntaxhighlight>
=={{header|Pascal}}==
<
Program FileTruncate;
Line 593 ⟶ 1,054:
writeln('File "', filename, '" truncated at position ', position, '.');
end.
</syntaxhighlight>
Output:
<pre>
Line 602 ⟶ 1,063:
=={{header|Perl}}==
<
open FOO, ">>file" or die;
truncate(FOO, 1234);
Line 608 ⟶ 1,069:
# Truncate a file to 567 bytes.
truncate("file", 567);</
=={{header|Phix}}==
In honour of this very task, there is now (0.8.0+) a set_file_size() builtin, for the grubby/cross-platform details see builtins/pfile.e (an autoinclude)<br>
It will pad or truncate as needed.
<!--<syntaxhighlight lang="phix">(notonline)-->
<span style="color: #008080;">without</span> <span style="color: #008080;">js</span> <span style="color: #000080;font-style:italic;">-- (file i/o)</span>
<span style="color: #0000FF;">?</span><span style="color: #7060A8;">get_file_size</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"test.txt"</span><span style="color: #0000FF;">)</span>
<span style="color: #0000FF;">?</span><span style="color: #000000;">set_file_size</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"test.txt"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">100</span><span style="color: #0000FF;">)</span>
<span style="color: #0000FF;">?</span><span style="color: #7060A8;">get_file_size</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"test.txt"</span><span style="color: #0000FF;">)</span>
<span style="color: #0000FF;">?</span><span style="color: #000000;">set_file_size</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"test.txt"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1024</span><span style="color: #0000FF;">)</span>
<span style="color: #0000FF;">?</span><span style="color: #7060A8;">get_file_size</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"test.txt"</span><span style="color: #0000FF;">)</span>
<!--</syntaxhighlight>-->
{{out}} (annotated, repeatable, assumes test.txt already exists)
<pre>
--1024
--1 (true)
--100
--1 (true)
--1024
</pre>
=={{header|PicoLisp}}==
On the 64-bit version, we can call the native runtime library:
<
(native "@" "truncate" 'I File Len) )</
Otherwise (on all versions), we call the external truncate command:
<
(call "truncate" "-s" Len File) )</
=={{header|PL/I}}==
<syntaxhighlight lang="text">
/* Parameters to be read in by the program are: */
/* 1. the name of the file to be truncated, and */
Line 662 ⟶ 1,129:
end;
end truncate_file;
</syntaxhighlight>
=={{header|PowerBASIC}}==
Line 669 ⟶ 1,136:
While PowerBASIC can use the QuickBASIC version of <code>truncateFile</code>, PB provides an easier way to do this, via the <code>SETEOF</code> function -- but since <code>SETEOF</code> will extend a file if it is not as long as specified, we still need to wrap it in a <code>SUB</code> to meet this task's specifications.
<
IF LEN(DIR$(file)) THEN
DIM f AS LONG
Line 685 ⟶ 1,152:
ERROR 53 'File not found
END IF
END SUB</
=={{header|Powershell}}==
<syntaxhighlight lang="powershell">Function Truncate-File(fname) {
$null | Set-Content -Path "$fname"
}
</syntaxhighlight>
=={{header|PureBasic}}==
PureBasic has the internal function [http://www.purebasic.com/documentation/file/truncatefile.html TruncateFile] that cuts the file at the current file position and discards all data that follows.
<
Protected fh, pos, i
If FileSize(File$) < length
Line 701 ⟶ 1,174:
EndIf
ProcedureReturn #True
EndProcedure</
=={{header|
<syntaxhighlight lang="python">
def truncate_file(name, length):
if not os.path.isfile(name):
return False
if length >= os.path.getsize(name):
return False
with open(name, 'ab') as f:
f.truncate(length)
return True
</syntaxhighlight>
=={{header|R}}==
<syntaxhighlight lang="r">
truncate_file <- function(filename, n_bytes) {
# check file exists and size is greater than n_bytes
stopifnot(
"file does not exist"= file.exists(filename),
"not enough bytes in file"= file.size(filename) >= n_bytes
)
# read bytes from input file
input.con <- file(filename, "rb")
bindata <- readBin(input.con, integer(), n=n_bytes/4)
close(input.con)
# write bytes to temporary file
tmp.filename <- tempfile()
output.con <- file(tmp.filename, "wb")
writeBin(bindata, output.con)
close(output.con)
# double check that everything worked before overwriting original file
stopifnot(
"temp file is not expected size"= file.size(tmp.filename) == n_bytes
)
# overwrite input file with temporary file
file.rename(tmp.filename, filename)
}
</syntaxhighlight>
=={{header|Racket}}==
Line 713 ⟶ 1,224:
Racket has a <tt>file-truncate</tt> function that expects an open port and truncate its associated file. Note that it can also extend the file, and the code below prints a warning in that case.
<syntaxhighlight lang="racket">
#lang racket
Line 721 ⟶ 1,232:
(call-with-output-file* file #:exists 'update
(λ(o) (file-truncate o size))))
</syntaxhighlight>
=={{header|Raku}}==
(formerly Perl 6)
{{Works with|rakudo|2016.07}}
<syntaxhighlight lang="raku" line>use NativeCall;
sub truncate(Str, int32 --> int32) is native {*}
sub MAIN (Str $file, Int $to) {
given $file.IO {
.e or die "$file doesn't exist";
.w or die "$file isn't writable";
.s >= $to or die "$file is not big enough to truncate";
}
truncate($file, $to) == 0 or die "Truncation was unsuccessful";
}</syntaxhighlight>
The external <code>truncate</code> routine could be replaced with the following line (in which case no need for <code>NativeCall</code>):
<syntaxhighlight lang="raku" line>spurt $file, slurp($file).substr($to);</syntaxhighlight>
=={{header|REXX}}==
Line 732 ⟶ 1,262:
::::* then erased (deleted),
::::* then written to.
<
parse arg siz FID /*
FID=strip(FID) /*elide FID leading/trailing blanks.
if siz=='' then call ser "No truncation size was specified (1st argument)."
if FID=='' then call ser "No fileID was specified (2nd argument)."
if \datatype(siz,'W') then call ser "trunc size isn't an integer: " siz
if siz<1 then call ser "trunc size isn't a positive integer: " siz
_=charin(FID,1,siz+1) /*position file and read a wee bit more*/
#=length(_) /*get the length of the part just read.*/
if #==0 then call ser "the specified file doesn't exist: " FID
if #<siz then call ser "the file is smaller than trunc size: " #
call lineout FID /*close the file used, just to be safe.*/
'ERASE' FID /*invoke a command to delete the file */
call lineout FID /*close the file, maybe for REXX's use.*/
call charout FID, left(_,siz), 1 /*write a truncated version of the file*/
call lineout FID /*close the file used, just to be safe.*/
say 'file '
exit /*stick a fork in it, we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
ser: say '***error
For this example, Windows/XP and Windows 7 operating systems were used, the program was tested with:
:::* Personal REXX
Line 765 ⟶ 1,295:
===with memory constraints===
<
parse arg siz FID /*
FID=strip(FID) /*elide FID leading/trailing blanks.
if siz=='' then call ser "No truncation size was specified (1st argument)."
if FID=='' then call ser "No fileID was specified (2nd argument)."
if \datatype(siz,'W') then call ser "trunc size isn't an integer: " siz
if siz<1 then call ser "trunc size isn't a positive integer: " siz
chunk=4000 /*read the file with this "buffer" size*/
call charin fid,1,0 /*position the file pointer to byte # 1*/
_= /* [↓] read while the length data<siz.*/
do while length(_)<=siz /* [↓] have we reached End-Of-File ? */
buffer=charin(FID,,chunk)
if #==0 then call ser "the specified file doesn't exist: " FID
if #<siz then call ser "the file is smaller than trunc size: " #
call lineout FID /*close the file used, just to be safe.*/
'ERASE' FID /*invoke a command to delete the file */
call lineout FID /*close the file, maybe for REXX's use.*/
call charout FID, left(_,siz), 1 /*write a truncated version of the file*/
call lineout FID /*close the file used, just to be safe.*/
say 'file '
exit /*stick a fork in it, we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
ser: say '***error
'''output''' is identical to the 1<sup>st</sup> REXX version. <br><br>
=={{header|Ring}}==
<syntaxhighlight lang="ring">
file = "C:\Ring\ReadMe.txt"
fp = read(file)
fpstr = left(fp, 100)
see fpstr + nl
write(file, fpstr)
</syntaxhighlight>
Output:
<pre>
The Ring Programming Language
http://ring-lang.net/
Version 1.0
Release Date : January 25, 2016
</pre>
=={{header|Ruby}}==
This only works with some platforms. If truncation is not available, then Ruby raises NotImplementedError.
<
File.open("file", "ab")
f.truncate(1234)
f << "Killroy was here" # write to file
end # file is closed now.
#
File.truncate("file", 567)</
=={{header|Rust}}==
<syntaxhighlight lang="rust">use std::path::Path;
use std::fs;
fn truncate_file<P: AsRef<Path>>(filename: P, filesize: usize) -> Result<(), Error> {
use Error::*;
let file = fs::read(&filename).or(Err(NotFound))?;
if filesize > file.len() {
return Err(FilesizeTooSmall)
}
fs::write(&filename, &file[..filesize]).or(Err(UnableToWrite))?;
Ok(())
}
#[derive(Debug)]
enum Error {
/// File not found
NotFound,
/// Truncated size would be larger than the current size
FilesizeTooSmall,
/// Likely due to having read but not write permissions
UnableToWrite,
}</syntaxhighlight>
=={{header|Scala}}==
{{libheader|Scala}}<
object TruncFile extends App {
Line 812 ⟶ 1,388:
outChan.truncate(newSize)
}
}</
=={{header|Sidef}}==
<
var file = File
len > file.size ->
&& die "The provided length is greater than the length of the file";
file.truncate(len);
}
# truncate "file.ext" to 1234 bytes
truncate("file.ext", 1234);</
=={{header|Standard ML}}==
{{works with|Unix}}
This function behaves similarly to the ''truncate'' tool from the [[GNU]] coreutils: If the file does not exist yet, or the target length is larger than the current file size, the extended area appears zero-filled (usually resulting in a sparse file).
<syntaxhighlight lang="sml">local
open Posix.FileSys
val perm = S.flags [S.irusr, S.iwusr, S.irgrp, S.iwgrp, S.iroth, S.iwoth]
in
fun truncate (path, len) =
let
val fd = createf (path, O_WRONLY, O.noctty, perm)
in
ftruncate (fd, len); Posix.IO.close fd
end
end</syntaxhighlight>
=={{header|Tcl}}==
<
set f [open "file" r+]; # Truncation is done on channels
chan truncate $f 1234; # Truncate at a particular length (in bytes)
close $f</
=={{header|UNIX Shell}}==
The dd(1) command can truncate a file. Because dd(1) would create the file, this example runs ls(1). If the file does not exist, then ls(1) prints an error. If the file exists, then dd(1) truncates the file or prints an error. Unix can extend a file, so there is no error if the length increases.
<
ls myfile >/dev/null &&
dd if=/dev/null of=myfile bs=1 seek=1440k</
----
Some systems have a truncate(1) command ([http://www.freebsd.org/cgi/man.cgi?query=truncate&apropos=0&sektion=0&manpath=FreeBSD+8.2-RELEASE&format=html FreeBSD truncate(1)], [http://www.gnu.org/software/coreutils/manual/html_node/truncate-invocation.html#truncate-invocation GNU truncate(1)]).
<
truncate -s 1440k myfile</
----
Pure bourne-shell approach (cross-OS, no truncate(1) binary required)
<
# 1. simplest one-liner
-bash$ >file
Line 935 ⟶ 1,526:
abc+ echo _EOF_
_EOF_
</syntaxhighlight>
NOTE[4]: Designed for regular text files. Does not work when files contain: chars 0x00 and 0xFF as of bash 4.2 - these chars are treated differently in read -N. For this reason use of method#4 is not prefer over dd(1) or truncate(1) when using binary files, or large files. [4b] http://unix.stackexchange.com/questions/8618/script-that-keep-reading-a-stream,[4a] https://groups.google.com/forum/#!topic/gnu.bash.bug/a2rjQHpQYSU
=={{header|VBScript}}==
<syntaxhighlight lang="vb">
Sub truncate(fpath,n)
'Check if file exist
Set objfso = CreateObject("Scripting.FileSystemObject")
If objfso.FileExists(fpath) = False Then
WScript.Echo fpath & " does not exist"
Exit Sub
End If
content = ""
'stream the input file
Set objinstream = CreateObject("Adodb.Stream")
With objinstream
.Type = 1
.Open
.LoadFromFile(fpath)
'check if the specified size is larger than the file content
If n <= .Size Then
content = .Read(n)
Else
WScript.Echo "The specified size is larger than the file content"
Exit Sub
End If
.Close
End With
'write the truncated version
Set objoutstream = CreateObject("Adodb.Stream")
With objoutstream
.Type = 1
.Open
.Write content
.SaveToFile fpath,2
.Close
End With
Set objinstream = Nothing
Set objoutstream = Nothing
Set objfso = Nothing
End Sub
'testing
Call truncate("C:\temp\test.txt",30)
</syntaxhighlight>
=={{header|Wren}}==
{{libheader|Wren-ioutil}}
<syntaxhighlight lang="wren">import "./ioutil" for FileUtil
var fileName = "temp.txt"
// create a file of length 26 bytes
FileUtil.write(fileName, "abcdefghijklmnopqrstuvwxyz")
System.print("Contents before truncation: %(FileUtil.read(fileName))")
// truncate file to 13 bytes
FileUtil.truncate(fileName, 13)
System.print("Contents after truncation : %(FileUtil.read(fileName))")
// attempt to truncate file to 20 bytes
FileUtil.truncate(fileName, 20)
System.print("Contents are still : %(FileUtil.read(fileName))")</syntaxhighlight>
{{out}}
<pre>
Contents before truncation: abcdefghijklmnopqrstuvwxyz
Contents after truncation : abcdefghijklm
Contents are still : abcdefghijklm
</pre>
=={{header|XPL0}}==
Works for binary files.
<syntaxhighlight lang="xpl0">int I, Size, FD;
char C, FN(80), Array;
[I:= 0; \get file name from command line
loop [C:= ChIn(8);
if C = $20 \space\ then quit;
FN(I):= C;
I:= I+1;
];
FN(I):= 0;
Size:= IntIn(8); \get number of bytes from command line
if Size = 0 then [Text(0, "Length not found (or zero)"); exit 1];
Trap(false); \disable abort on errors
FD:= FOpen(FN, 0); \open specified file for input
FSet(FD, ^i);
OpenI(3);
if GetErr then [Text(0, "File not found"); exit 1];
Array:= Reserve(0); \64MB available if no procedures are called
for I:= 0 to Size-1 do \read specified number of bytes
[Array(I):= ChIn(3);
if GetErr then [Text(0, "File is too short"); exit 1];
]; \if end of file encountered, show error
FClose(FD);
FD:= FOpen(FN, 1); \open file by same name for output
FSet(FD, ^o);
OpenO(3);
if GetErr then [Text(0, "Output error"); exit 1];
for I:= 0 to Size-1 do ChOut(3, Array(I));
Close(3);
]</syntaxhighlight>
=={{header|ZX Spectrum Basic}}==
Line 943 ⟶ 1,637:
We can truncate files that were saved as binary. We don't know the length of the original file, so if the provided length is longer, then the file will be extended.
<
20 INPUT "Which file do you want to truncate?";f$
30 PRINT "Start tape to load file to truncate."
Line 950 ⟶ 1,644:
60 PRINT "Please rewind the tape and press record."
70 SAVE f$ CODE 30000,n
80 STOP</
{{omit from|GUISS}}
{{omit from|HTML}}
|