How to Write to a File in Perl (open/print, modes, safety, and best practices)
Question
how to write to file in perl
How to write to a file in Perl
Category: Perl
Difficulty: Beginner (with intermediate best practices)
Tags: perl, file-io, open, print, say, append, encoding, autodie, flock, atomic-write, syswrite
Overview
Writing to a file in Perl is built around three ideas:
(1) open a filehandle with the correct mode,
(2) write using print / say / printf (or lower-level syswrite),
and (3) close the filehandle and handle errors.
Perl can write to files efficiently and safely, but many bugs come from skipping error checks,
using the old two-argument form of open, mixing encodings, or accidentally truncating a file.
The essential pattern
The modern, recommended pattern is the three-argument open with a lexical filehandle:
open my $fh, '>', $path or die "open($path): $!";
print {$fh} "Hello\n";
close $fh or die "close($path): $!";
The three arguments matter: the mode ('>', '>>', etc.) is separate from the filename.
This avoids a class of security problems and parsing surprises that come with older forms.
File modes you will use most
- Overwrite / create:
'>'(truncates an existing file to zero length) - Append / create:
'>>'(writes go to end of file) - Read/write:
'+<'(update without truncation; you manage seeking) - Read/write with truncation:
'+>'(truncates like'>')
If you only remember one pitfall: '>' truncates immediately when you open the file.
If you meant to add a line to an existing log, you want '>>', not '>'.
Example 1: Create/overwrite a file and read it back (runnable)
This example writes a small file using print, closes it, then reopens it for reading and prints
the contents to STDOUT so you can see exactly what was written.
#!/usr/bin/env perl
use strict;
use warnings;
my $path = 'example1.txt';
open my $out, '>', $path or die "open for write ($path): $!";
print {$out} "Line 1: Hello from Perl\n";
print {$out} "Line 2: Writing to a file is just printing to a filehandle\n";
close $out or die "close ($path): $!";
open my $in, '<', $path or die "open for read ($path): $!";
while (my $line = <$in>) {
print $line;
}
close $in or die "close ($path): $!";
Expected output (STDOUT):
Line 1: Hello from Perl
Line 2: Writing to a file is just printing to a filehandle
Writing APIs: print, say, printf, syswrite
print: writes strings exactly as provided (no newline added automatically).say: likeprintbut adds a newline; enable withuse feature 'say';(oruse v5.10;and above).printf: formatted output, like Cprintf.syswrite: unbuffered, low-level writes; you handle partial writes and offsets.
For most scripts, print/say/printf are correct and simplest.
Use syswrite when you need precise control (binary protocols, performance tuning, non-blocking IO).
Example 2: Append to a file (and why it matters) (runnable)
Appending is ideal for logs. The key difference is the mode: '>>' does not truncate.
#!/usr/bin/env perl
use strict;
use warnings;
my $path = 'example2.log';
# Start fresh for the demo
open my $start, '>', $path or die "open ($path): $!";
print {$start} "[init] log started\n";
close $start or die "close ($path): $!";
# Append two lines
open my $app, '>>', $path or die "open for append ($path): $!";
print {$app} "[info] first appended line\n";
print {$app} "[info] second appended line\n";
close $app or die "close ($path): $!";
# Show file content
open my $in, '<', $path or die "open for read ($path): $!";
print while (<$in>);
close $in or die "close ($path): $!";
Expected output (STDOUT):
[init] log started
[info] first appended line
[info] second appended line
Encoding and text vs binary
Perl distinguishes bytes (raw) from characters (text). Files on disk are bytes, while your Perl strings may represent characters. If you write non-ASCII text (accented characters, emojis, many languages), you should choose an encoding layer explicitly (UTF-8 is common):
open my $fh, '>:encoding(UTF-8)', $path or die $!;
print {$fh} "café\n";
close $fh or die $!;
If you do not set an encoding layer, behavior can vary depending on your data and environment, and you may
see warnings about wide characters, or you may write mojibake (garbled text). For binary files (images, zip,
protocol frames), do not use :encoding; instead use :raw.
Example 3: Safer writing with UTF-8 and an atomic replace pattern (runnable)
When writing configuration or data files that must not be left half-written (power loss, crash, deploy kill), a common best practice is: write to a temporary file in the same directory, close it, then rename it over the destination. On most systems, rename within the same filesystem is atomic.
#!/usr/bin/env perl
use strict;
use warnings;
use File::Temp qw(tempfile);
my $path = 'example3.txt';
my ($tmp_fh, $tmp_path) = tempfile('example3.tmp.XXXX', UNLINK => 0);
# Write UTF-8 text safely to the temp file
binmode($tmp_fh, ':encoding(UTF-8)') or die "binmode: $!";
print {$tmp_fh} "Name: café\n";
print {$tmp_fh} "Status: OK\n";
close $tmp_fh or die "close temp: $!";
# Atomically replace the target
rename $tmp_path, $path or die "rename($tmp_path -> $path): $!";
# Show final content
open my $in, '<:encoding(UTF-8)', $path or die "open for read ($path): $!";
print while (<$in>);
close $in or die "close ($path): $!";
Expected output (STDOUT):
Name: café
Status: OK
Best practices
- Use three-argument
open:open my $fh, '>', $path, not old two-argument forms. - Use lexical filehandles:
my $fhkeeps scope clear and avoids globals. - Check errors on
openandclose:closecan fail (buffer flush, NFS, full disk). - Prefer
autodiein scripts: it turns common IO failures into exceptions automatically. - Choose encoding intentionally:
'>:encoding(UTF-8)'for text;'>:raw'for bytes. - Be explicit about truncation: choose
'>'vs'>>'consciously. - Use file locking when multiple writers exist:
flockprevents interleaving/overwrites in many cases. - Write atomically for critical files: temp + rename avoids partially written destinations.
Quick note on autodie
In many scripts you can replace repetitive or die checks with:
use autodie;
open my $fh, '>', $path;
print {$fh} "...";
close $fh;
This does not remove the need to think about modes, encoding, or atomicity, but it reduces boilerplate.
Pitfalls and how to avoid them
- Accidental truncation: opening with
'>'wipes the file immediately; use'>>'for logs. - Not checking
close: errors can occur on flush; always check when data matters. - Using two-argument
openwith user input: can be parsed as a pipe; use three arguments. - Encoding warnings / mojibake: set
:encoding(UTF-8)for text and be consistent on read/write. - Concurrent writers: without
flock, two processes can interleave lines or overwrite; lock if needed. - Buffered output surprises: output may not hit disk immediately; call
closeor enable autoflush for interactive logs. - Permissions and umask: file creation may fail or be unreadable; handle
$!and know your runtime user.
When to use flock (briefly)
If multiple processes/threads might write the same file, you often want:
use Fcntl qw(:flock);
open my $fh, '>>', $path or die $!;
flock($fh, LOCK_EX) or die $!;
print {$fh} "one complete record\n";
close $fh or die $!;
This reduces garbled logs, but note that locking behavior can vary on network filesystems.
Summary
To write to a file in Perl, use a lexical filehandle and the three-argument open, pick the right mode
('>' to overwrite, '>>' to append), write with print/say/printf, and always handle
errors on open and close. For real-world robustness, be explicit about encoding, consider locks for
concurrent writers, and use atomic replace for important files.
Verified Code
Executed in a sandbox to capture real output. • 24ms
Line 1: Hello from Perl
Line 2: Writing to a file is just printing to a filehandle
(empty)Was this helpful?
Related Questions
- How to Load a Module in Perl (use, require, @INC, and Best Practices)
- How to Run Perl Code on macOS (Terminal, Scripts, Shebangs, Modules, and Common Pitfalls)
- How to Add Elements to an Array in Perl (push, unshift, splice, indexing, and arrayrefs)
- How to Install Perl Modules on Windows (CPAN, cpanm, Strawberry Perl, ActiveState, local::lib)
- How to Compare Strings in Perl (eq/ne, lt/gt, cmp, case-insensitive, Unicode)
- How to Check If a Perl Module Is Installed (and Loadable)