Open, sysopen, read, sysread... oh my!

TL;DR

open and read are usually fine.

In recent post Random bytes and co. I wrote a function to read exactly 16 bytes from /dev/urandom:

sub salt_please {
   open my $fh, '< :raw :bytes', '/dev/urandom'
      or die "open('/dev/urandom'): $!\n";
   my $retval = '';
   while ((my $len = length $retval) < 16) {
      read($fh, $retval, 16 - $len, $len) // die "read(): $!\n"
   }
   close $fh;
   return $retval;
}

My first thought was to use sysopen and sysread, but then I took a look at perlopentut and figured that it was not needed.

Then of course I wondered… when should I use one or the other?!?

Here’s something I collected.

They don’t pair

The first thing is that there is no pairing, i.e. you can use read with filehandles opened with sysopen, and use sysread with filehandles opened with open.

open is almost certainly good

What’s the difference between open and sysopen in Perl?

The bottom line is that everyday usage for a multitude of files is fine with open. As put in this answer:

Unless you are working with a specific device that requires some special flags to be passed at open(2) time, for ordinary files on disk you should be fine with open.

One comment in the answer provides an excellent example of using sysopen over open:

[…] consider O_WRONLY|O_EXCL|O_CREAT combo, i.e. “create and write if not exists”. Using -f ... or open ... instead is just asking for race condition.

So there I have it, to read (binary) data from /dev/urandom I will just open passing :raw :binary as suggested in perlopentut.

read is almost certainly good

What is the difference between read and sysread?

I’ll just copy-paste the author’s conclusions:

  • read works with any Perl file handle, while sysread is limited to Perl file handles mapped to a system file handle/descriptor.
  • read isn’t compatible with select (I’m referring to the 4-argument one called by IO::Select), while sysread is compatible with select.
  • read can perform decoding for you, while sysread requires that you do your own decoding.
  • read should be faster for very small reads, while sysread should be faster for very large reads.

Maybe I’m oversimplifying, but I think I’ll leave sysread for sockets etc. and stick to read if I’m reading local stuff.


Comments? Octodon, , GitHub, Reddit, or drop me a line!