I/O · Fixed-length data

syswrite#

Write bytes to a filehandle with the raw write(2) system call, bypassing Perl’s buffered I/O.

syswrite hands LENGTH bytes from SCALAR directly to the kernel via write(2), skipping the PerlIO buffering that print, printf, and write go through. The kernel may accept fewer bytes than requested — syswrite returns whatever it actually wrote, and well-written code always checks. If LENGTH is omitted, the whole SCALAR is written. An optional OFFSET starts the write at a position other than the beginning of the string.

Synopsis#

syswrite FILEHANDLE, SCALAR, LENGTH, OFFSET
syswrite FILEHANDLE, SCALAR, LENGTH
syswrite FILEHANDLE, SCALAR

What you get back#

The number of bytes actually written, or undef on error (with $! set). The returned count can be less than LENGTH. This is normal on pipes, sockets, and non-blocking handles; it is not an error. Code that needs every byte delivered must loop:

my $off = 0;
my $len = length $buf;
while ($off < $len) {
    my $n = syswrite $fh, $buf, $len - $off, $off;
    defined $n or die "write failed: $!";
    $off += $n;
}

A return of 0 is legal and means “no bytes written this call, try again” — not end-of-stream. undef is the only error signal.

Global state it touches#

  • $! — set on error (any return of undef).

  • No interaction with $,, $\, or $|. syswrite does not format, does not append record separators, and does not honour the autoflush flag because there is no buffer to flush — bytes go straight to the kernel.

  • No interaction with the selected filehandle from select. FILEHANDLE is mandatory; there is no default.

Examples#

Write a string verbatim to STDOUT, no separators added:

syswrite STDOUT, "hello\n";        # 6 bytes written

Write a fixed-size record and check for a short write:

my $rec = pack "A8 N", $name, $id;   # 12 bytes
my $n = syswrite $fh, $rec;
defined $n or die "syswrite: $!";
$n == length $rec or die "short write: $n of ${\length $rec}";

Write from the middle of a buffer with OFFSET. Useful inside a drain loop where $off tracks how much has been accepted so far:

my $buf = "ABCDEFGHIJ";
syswrite $fh, $buf, 4, 3;          # writes "DEFG"

Negative OFFSET counts from the end:

my $buf = "ABCDEFGHIJ";
syswrite $fh, $buf, 3, -4;         # writes "GHI"

Write to a non-blocking socket and handle EAGAIN:

use Errno qw(EAGAIN EWOULDBLOCK);

my $n = syswrite $sock, $buf;
if (!defined $n) {
    if ($! == EAGAIN || $! == EWOULDBLOCK) {
        # kernel buffer full — try again after select()
    } else {
        die "syswrite: $!";
    }
}

Edge cases#

  • Do not mix with buffered I/O on the same handle. syswrite bypasses PerlIO, but print, printf, write, seek, tell, and eof all go through the :perlio and :crlf buffering layers. Interleaving them on one handle corrupts the output order. Pick one mode per handle. If you must mix, use read / sysread symmetry rules and be deliberate.

  • Short writes are normal. Pipes, sockets, terminals, and non-blocking handles routinely accept fewer bytes than offered. The drain-loop idiom above is the correct pattern for any handle where short writes matter.

  • Return value 0 means the kernel accepted zero bytes this call. It is not end-of-stream and not an error; retry.

  • Length larger than available data: if LENGTH exceeds length(SCALAR) - OFFSET, only the available bytes are written and that count is returned.

  • Empty SCALAR: if SCALAR has length zero, OFFSET must be 0. Any other value raises an exception.

  • :utf8 and :encoding(...) layers raise an exception. syswrite operates on bytes, not characters, and refuses any handle carrying a UTF-8 encoding layer. :encoding(...) implicitly adds :utf8, so it is equally forbidden. Use binmode to remove the layer, or write through print instead.

  • Characters above U+00FF on a byte-mode handle also raise an exception — there is no way to serialise a codepoint greater than 0xFF as a single byte. Encode the string explicitly before calling syswrite:

    use Encode qw(encode);
    syswrite $fh, encode("UTF-8", $text);
    
  • Broken pipe / closed socket raises SIGPIPE. The default action terminates the process. Install $SIG{PIPE} = 'IGNORE' (or a handler) to turn it into a normal syswrite error with $! set to EPIPE.

  • Closed filehandle returns undef with $! set to "Bad file descriptor"; under use warnings a syswrite() on closed filehandle warning is emitted.

Differences from upstream#

Fully compatible with upstream Perl 5.42.

See also#

  • sysread — the read counterpart; same buffer-bypassing semantics and same short-read caveat

  • sysopen — open a handle at the open(2) level so syswrite can talk to it without any PerlIO translation layers in the way

  • sysseek — reposition the handle using lseek(2), paired with syswrite for random-access I/O on raw handles

  • print — the buffered counterpart you almost always want instead; honours $,, $\, and $|

  • binmode — remove a :utf8 or :encoding(...) layer from a handle so syswrite can be used on it

  • $! — inspect after a undef return to distinguish EAGAIN from a real failure