--- name: truncate signature: 'truncate FILEHANDLE, LENGTH' signatures: - 'truncate FILEHANDLE, LENGTH' - 'truncate EXPR, LENGTH' since: 5.0 status: documented categories: ["I/O"] --- ```{index} single: truncate; Perl built-in ``` *[I/O](../perlfunc-by-category)* # 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`](seek) before the next write. ## Synopsis ```perl truncate FILEHANDLE, LENGTH truncate EXPR, LENGTH ``` ## What you get back `1` on success, [`undef`](undef) on failure with [`$!`](../perlvar) set to the underlying `errno`. A missing platform implementation raises an exception rather than returning [`undef`](undef); that is an install-time property, not something to branch on at runtime. ```perl 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, LENGTH`** — `EXPR` 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 - [`$!`](../perlvar) 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: ```perl 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: ```perl truncate "scratch.dat", 0 or die "truncate scratch.dat: $!"; ``` Rotate a pre-allocated buffer file down to the used portion: ```perl my $used = tell $fh; # bytes actually written truncate $fh, $used or die "truncate: $!"; ``` Extend a file to a fixed size (sparse hole on Linux): ```perl 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`](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`](undef) with [`$!`](../perlvar) 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`](open) — produce a writable filehandle suitable for the filehandle form of `truncate` - [`seek`](seek) — reposition the handle after truncating, before writing again - [`tell`](tell) — current offset, useful as the `LENGTH` argument when trimming to "what I have written so far" - [`sysopen`](sysopen) — lower-level open when you need explicit flags (`O_TRUNC` truncates at open time; `truncate` is the after-the-fact equivalent) - [`unlink`](unlink) — reach for this instead when you want the file gone, not merely emptied - [`$!`](../perlvar) — `errno` on failure