I/O

seek#

Reposition a filehandle for random-access reads or writes.

seek moves FILEHANDLE’s read/write pointer to a new byte offset, mirroring the C fseek(3) call. After a successful seek, the next read, readline, or print on the handle starts from the new position. POSITION is a signed byte offset; WHENCE selects the anchor it is measured from.

Synopsis#

seek FILEHANDLE, POSITION, WHENCE
seek $fh, 0, 0             # rewind to start
seek $fh, 0, 1             # no-op: clear EOF, keep position
seek $fh, -1024, 2         # 1024 bytes before EOF

What you get back#

1 on success, a false value on failure (with $! set). Always check the return value — seeking past a short file, on an unseekable handle (pipe, socket, TTY), or after a write error all fail here rather than at the next read.

seek $fh, $offset, 0
    or die "seek to $offset failed: $!";

WHENCE values#

WHENCE is an integer with three meaningful values. Use the symbolic constants from Fcntl for readability:

  • 0 / SEEK_SETPOSITION is measured from the start of the file. POSITION must be non-negative.

  • 1 / SEEK_CURPOSITION is added to the current position. Negative values move backward, positive values forward. seek $fh, 0, 1 is the canonical “move nowhere, but clear EOF” idiom.

  • 2 / SEEK_ENDPOSITION is added to the end-of-file offset. POSITION is typically zero or negative.

use Fcntl qw(SEEK_SET SEEK_CUR SEEK_END);

seek $fh, 0,     SEEK_SET;   # rewind
seek $fh, 0,     SEEK_END;   # go to EOF (e.g. to append)
seek $fh, -$n,   SEEK_CUR;   # $n bytes back from here

Bytes, not characters#

Even when the handle has a character-oriented layer such as :encoding(UTF-8), seek, tell, and the sysseek family operate on byte offsets. A seek to a byte offset that lands in the middle of a multi-byte sequence will produce decoding errors or replacement characters on the next read.

If you need to position by characters, read forward from a known byte boundary rather than trying to translate character counts to byte offsets. tell values are safe to feed back into seek because they were produced at byte boundaries the I/O layer already crossed cleanly.

Global state it touches#

  • $! — set to the system error message on failure.

  • The filehandle’s PerlIO buffer is discarded on success, so any data read ahead by buffering is dropped and the next read pulls fresh bytes from the underlying file.

  • The end-of-file flag on FILEHANDLE is cleared on success, even when POSITION and WHENCE leave the position unchanged.

Examples#

Rewind to the start of a file before re-reading it:

seek $fh, 0, 0 or die "rewind failed: $!";
while (my $line = <$fh>) { ... }

Append by positioning at end-of-file, then writing. For append-only use, prefer opening with >> — this form is for handles already open for read-write:

seek $fh, 0, 2 or die $!;           # SEEK_END
print $fh "appended line\n";

Read a fixed-width record by index, where each record is 128 bytes:

my $record = 42;
seek $fh, $record * 128, 0 or die $!;
read $fh, my $buf, 128;

Emulate tail -f — the seek $fh, 0, 1 resets the EOF condition so the next readline retries the file for new data:

while (1) {
    while (my $line = <$fh>) { print $line }
    sleep 1;
    seek $fh, 0, 1;                 # clear EOF, keep position
}

Save a position with tell, read ahead, then restore:

my $mark = tell $fh;
my $peek = <$fh>;
seek $fh, $mark, 0 or die $!;       # back to where we were

Edge cases#

  • Unseekable handles: pipes, sockets, TTYs, and most special devices return false and set $! to ESPIPE (Illegal seek). Check the return value; do not assume every filehandle is seekable.

  • Mixing reads and writes on the same handle on a file opened +< or +> requires a seek (or tell, or an explicit flush) when switching direction. A WHENCE of 1 with POSITION of 0 is the usual no-op separator:

    seek $fh, 0, 1;                   # allowed to switch read <-> write
    
  • Seeking past EOF on a file opened for writing is legal and creates a sparse hole up to POSITION on filesystems that support holes; the next write fills part of the hole and the bytes in between read back as "\0".

  • sysread / syswrite users: do not mix seek with sysread or syswrite. seek operates on the PerlIO buffer layer; the unbuffered sys-family bypasses it, so their effective positions drift apart. Use sysseek for handles you access through the sys-family.

  • Character offsets via arithmetic: multiplying a character count by an assumed encoding width is wrong for UTF-8 and other variable-width encodings. Use byte offsets obtained from tell, or read forward from a known boundary.

  • Directory handles: seek does not work on directory handles. Use seekdir with a position from telldir.

  • Closed filehandle: returns a false value and sets $!; under use warnings a seek() on closed filehandle warning is emitted.

Differences from upstream#

Fully compatible with upstream Perl 5.42.

See also#

  • tell — read the current byte offset; the value round-trips safely through seek with WHENCE 0

  • sysseek — unbuffered seek for handles accessed via sysread / syswrite; use this instead of seek when bypassing PerlIO

  • read — buffered fixed-length read; the natural partner for positioning by byte offset

  • readline — line-oriented read; seek $fh, 0, 1 before a retry is the tail -f idiom

  • eof — test for end-of-file; seek clears the EOF flag a prior read may have set

  • Fcntl — source of the SEEK_SET, SEEK_CUR, SEEK_END constants