I/O

telldir#

Return the current read position of a directory handle as an opaque token.

telldir reports where the next readdir on DIRHANDLE will pick up. The returned value is a bookmark, not a byte offset: hand it back to seekdir to resume iteration at the same entry, or discard it. The number has no arithmetic meaning — it is not an index into the directory, not a count of entries read, and not comparable across directory handles. Treat it the way you would treat the return value of tell on a file handle: opaque to you, meaningful only to the matching seekdir.

Synopsis#

telldir DIRHANDLE

What you get back#

An integer on success, undef on failure (for example, if DIRHANDLE is not an open directory handle). The integer is only guaranteed to round-trip through seekdir on the same open directory handle; closing and reopening the directory invalidates every previously returned token.

opendir my $dh, $path or die "opendir $path: $!";
my $pos = telldir $dh;
# ... readdir a few entries ...
seekdir $dh, $pos;           # back to where $pos was taken

Global state it touches#

Sets $! on failure.

Examples#

Bookmark a position, then return to it:

opendir my $dh, "." or die "opendir: $!";
readdir $dh;                 # consume "."
my $mark = telldir $dh;
my @rest = readdir $dh;      # drain the rest
seekdir $dh, $mark;
my @again = readdir $dh;     # same entries as @rest
closedir $dh;

Record a token before each entry so you can rewind one step:

opendir my $dh, $path or die "opendir $path: $!";
my $prev;
while (defined(my $entry = readdir $dh)) {
    last if $entry eq "STOP";
    $prev = telldir $dh;     # position *after* the current entry
}
seekdir $dh, $prev if defined $prev;

Rewinding to the start is better done with rewinddir than by remembering the token from before the first readdir:

opendir my $dh, $path or die "opendir $path: $!";
my @first_pass  = readdir $dh;
rewinddir $dh;               # cleaner than seekdir $dh, $start_token
my @second_pass = readdir $dh;

Check for failure explicitly when the handle might be closed:

my $pos = telldir $dh;
defined $pos or die "telldir failed: $!";

Edge cases#

  • Token is opaque. Do not compare, add, subtract, or persist the value. It is valid only for seekdir on the same open directory handle within the same process.

  • Not portable across handles. Two opendir calls on the same directory produce independent handles; a token from one is meaningless to the other.

  • Not stable across closedir / opendir. Reopening the directory starts a fresh iteration; old tokens no longer refer to anything.

  • Directory compaction. If the underlying filesystem or another process modifies the directory (adds, removes, or renames entries) between telldir and the matching seekdir, the resumed position may skip entries, repeat entries, or land on a different entry than the one originally bookmarked. This is a property of the C library telldir(3) / seekdir(3) pair and is not something Perl papers over. Snapshot the directory with readdir into a list if you need stability.

  • Closed or never-opened handle. Returns undef and sets $!.

  • Bareword vs. scalar handle. telldir DH and telldir $dh both work. The bareword form is a package global; the scalar form holds a reference to an anonymous directory handle created by opendir my $dh, ....

Differences from upstream#

Fully compatible with upstream Perl 5.42.

See also#

  • seekdir — the only consumer of a telldir token; restores DIRHANDLE to the bookmarked position

  • readdir — the iterator whose position telldir reports; advances the cursor that telldir observes

  • rewinddir — cheaper than seekdir to a start-of-stream token when you just want to iterate the directory again

  • opendir — creates the DIRHANDLE that telldir queries; every telldir token is tied to one open call

  • closedir — invalidates every telldir token for the handle

  • tell — the file-handle analogue; same opaque-token contract, different underlying system call