IO::Detect(3pm)
π IO::Detect π
okay bestie, so this lil page is all about IO::Detect, the Perl module whose whole personality is answering the question: is this a frickin' filehandle or what?! πβ¨
β¨ SYNOPSIS β¨
use IO::Detect;
if (is_filehandle $fh)
{
my $line = <$fh>;
}
πΈ DESCRIPTION πΈ
ngl, detecting whether a given scalar is a filehandle (or something filehandle-ish) in Perl is stupidly complicated. Like, absurdly. This module ~attempts~ to do it, but it probably falls short in some cases. π And the primary advantage of using it? It gives you somebody to blame (me) if your code can't detect a filehandle. You're welcome, bestie. π
The main use case for IO::Detect is when you're out here writing functions and you want to let the caller pass a file as an argument without being fussy about whether they hand you a file name or a file handle. Iconic, lowkey. π¦
π§ Functions
Every single one of these takes a single argument β or, if you call it with no argument at all, it operates on $_.
is_filehandle $thingβ Theoretically returns true if and only if$thingis a file handle, or may be treated as a filehandle. That includes blessed references to filehandles, things that inherit fromIO::Handle, etc.
It's never going to work 100%. What Perl lets you use as a filehandle is mysterious and, like, somewhat context-dependent, as this code right here illustrates:
my $fh = "STD" . "OUT";
print $fh "Hello World!\n";
is_filename $thingβ Returns true if$thingis aIO::Allobject orPath::Class::Entity, or "any non-reference, non-zero-length string with no line breaks". Why so loose? Because depending on your operating system, virtually anything can be used as a filename. (In fact, on many systems, including Linux, filenames can contain line breaks. However, this is unlikely to be intentional.) π
This function does not tell you whether $thing is an existing file on your system. It attempts to tell you whether $thing could possibly be a filename on some system somewhere. Vibes only, basically. β¨
is_fileuri $thingβ Returns true if$thingis a URI beginning withfile://. It allows for URI objects,RDF::Trine::Node::Resourceobjects, strings, and objects that overload stringification. π
This function actually returns an "interesting value of true". The value returned is a URI::file object. (yes, it's giving overachiever.)
as_filehandle $thing, $modeβ Returns$thingif it is a filehandle; otherwise opens it with mode$mode(croaking if it cannot be opened).$modedefaults to"<"(read access).
This function is not exported by default, you gotta request it explicitly:
use IO::Detect qw(as_filehandle);
You may even specify a different default mode, or import it several times with different names:
use IO::Detect
as_filehandle => { -as => 'as_filehandle_read', mode => '<' },
as_filehandle => { -as => 'as_filehandle_write', mode => '>' };
π Smart Matching
You can import three constants for use in smart matching:
use IO::Detect -smartmatch;
These constants are:
FileHandleFileNameFileUri
They can be used like this:
if ($file ~~ FileHandle)
{
...
}
Heads up though: there does exist a FileHandle package in Perl core. This module attempts to do the right thing so that FileHandle->new still works, but there are conceivably places this could go wrong, or be plain old confusing. π
Although is_filehandle and its friends support Perl 5.8 and above, smart match is only available in Perl 5.10 onwards. Noted. π
π Use with Scalar::Does
The smart match constants can also be used with Scalar::Does:
if (does $file, FileHandle)
{
...;
}
elsif (does $file, FileName)
{
...;
}
π«Ά Precedence
Because there is some overlap/ambiguity between what is a filehandle and what is a filename, etc, if you need to detect between them, I recommend checking is_filehandle first, then is_fileuri and falling back to is_filename. In that order, bestie, trust. π―
for ($file)
{
when (FileHandle) { ... }
when (FileUri) { ... }
when (FileName) { ... }
default { die "$file is not a file!" }
}
π Export
Like Scalar::Does, IO::Detect plays some tricks with namespace::clean to ensure that any functions it exports to your namespace are cleaned up when you're finished with them. Tidy!
π¦ Duck Typing
In some cases you might be happy to accept something less than a complete file handle. In that case you can import a customised "duck type" test...
use IO::Detect
-default,
ducktype => {
-as => 'is_slurpable',
methods => [qw(getlines close)],
};
sub do_something_with_a_file
{
my $f = shift;
if ( is_filehandle $f or is_slurpable $f )
{ ... }
elsif ( is_filename $f )
{ ... }
}
Duck type test functions only test that the argument is blessed and can do all of the specified methods. They don't test any other aspect of "filehandliness". That's it, that's the whole vibe check. π¦
π BUGS π
Please report any bugs to <http://rt.cpan.org/Dist/Display.html?Queue=IO-Detect>.
π SEE ALSO π
This module is an attempt to capture some of the wisdom from this PerlMonks thread <http://www.perlmonks.org/?node_id=980665> into executable code.
Various other modules that may be of interest, in no particular order... Scalar::Does, Scalar::Util, FileHandle, IO::Handle, IO::Handle::Util, IO::All, Path::Class, URI::file.
β¨ AUTHOR β¨
Toby Inkster <tobyink@cpan.org>.
π COPYRIGHT AND LICENCE π
This software is copyright (c) 2012-2014, 2017 by Toby Inkster.
This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.
π DISCLAIMER OF WARRANTIES π
THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
okay that's the whole thing, no cap π
this was IO::Detect, perl v5.40.1, dated 2025-08-04 β go detect some filehandles bestie, ily, bye π«Άβ¨πΈ
π¦ where this page comes from
- ubuntu resolute: libscalar-does-perl 0.203-4 Β· Artistic-1.0-Perl OR GPL-1.0-or-later
- ubuntu stonking: libscalar-does-perl 0.203-4 Β· Artistic-1.0-Perl OR GPL-1.0-or-later
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms