I/O

truncate#

Shorten (or extend) a file to an exact byte length.

truncate adjusts the size of the file opened on FILEHANDLE, or the file named by EXPR, so it is exactly LENGTH bytes long. Bytes past LENGTH are discarded. The file’s current read/write position is not changed — a handle sitting past the new end of file stays there, which is almost never what you want, so plan a seek before the next write.

Synopsis#

truncate FILEHANDLE, LENGTH
truncate EXPR, LENGTH

What you get back#

1 on success, undef on failure with $! set to the underlying errno. A missing platform implementation raises an exception rather than returning undef; that is an install-time property, not something to branch on at runtime.

truncate $fh, 0
    or die "truncate failed: $!";

Filehandle vs. filename form#

Two forms, chosen by what you already have in hand:

  • truncate FILEHANDLE, LENGTH — the handle must be open for writing (or read/write). Use this when the caller already owns an open write handle; it avoids a fresh open/close round-trip and works even after the file has been unlinked.

  • truncate EXPR, LENGTHEXPR is stringified as a pathname. The file is opened, truncated, and closed internally. Use this when you only have a path and do not need the handle afterwards.

Both forms require write permission on the target. On the filehandle form, that is a property of the open mode; on the pathname form, of the filesystem permissions.

LENGTH semantics#

  • LENGTH is in bytes, not characters. Encoding layers on the filehandle are irrelevant — the length argument goes straight to the OS.

  • LENGTH less than the current file size discards the tail.

  • LENGTH equal to the current size is a no-op that still succeeds.

  • LENGTH greater than the current size extends the file with a hole of zero bytes on filesystems that support sparse files, or with literal zero bytes otherwise. Upstream perlfunc calls this case undefined; in practice it behaves like POSIX ftruncate(2) on Linux, which is what pperl targets.

Global state it touches#

  • $! is set on failure to the underlying errno.

Examples#

Empty a logfile without closing the handle the rest of the program is still writing to:

open my $log, "+<", "app.log" or die $!;
truncate $log, 0 or die "truncate: $!";
seek $log, 0, 0;                # rewind; see "Position is not reset"

Truncate a file by name, no handle involved:

truncate "scratch.dat", 0
    or die "truncate scratch.dat: $!";

Rotate a pre-allocated buffer file down to the used portion:

my $used = tell $fh;            # bytes actually written
truncate $fh, $used
    or die "truncate: $!";

Extend a file to a fixed size (sparse hole on Linux):

open my $fh, ">", "image.raw" or die $!;
truncate $fh, 1024 * 1024 * 1024   # 1 GiB sparse file
    or die "truncate: $!";

Edge cases#

  • Position is not reset. After truncate $fh, 0, the handle still remembers whatever offset it had. A following print $fh ... without an intervening seek may write past the new end of file, leaving a zero-filled hole.

  • Read-only handle: truncating a handle opened with < fails with EBADF / EINVAL depending on the platform. Open with +< (read/write) or >> plus an appropriate mode if you need to truncate through the same handle you read from.

  • Negative LENGTH: the kernel rejects it and truncate returns undef with $! set to EINVAL.

  • Directory as EXPR: fails with EISDIR. truncate is strictly a file operation.

  • File unlinked but still open: the filehandle form works fine — the inode is still there as long as any handle holds it open.

  • LENGTH larger than current size: on Linux this extends with a sparse hole; reading the hole yields "\0" bytes. Upstream perlfunc flags this as undefined, so portable code should not rely on it.

  • Platform without ftruncate/truncate: raises an exception (The truncate function is unimplemented). Not a concern on pperl’s supported platform (Linux), but matters for portable code.

Differences from upstream#

Fully compatible with upstream Perl 5.42.

See also#

  • open — produce a writable filehandle suitable for the filehandle form of truncate

  • seek — reposition the handle after truncating, before writing again

  • tell — current offset, useful as the LENGTH argument when trimming to “what I have written so far”

  • sysopen — lower-level open when you need explicit flags (O_TRUNC truncates at open time; truncate is the after-the-fact equivalent)

  • unlink — reach for this instead when you want the file gone, not merely emptied

  • $!errno on failure