Perl file operations

Open and close files

Open file for reading

open(my $fh, '<', 'input.txt') or die "Cannot open file: $!";

while (my $line = <$fh>) {
    print $line;
}

close($fh);

Open file for writing

open(my $fh, '>', 'output.txt') or die "Cannot open file: $!";

print $fh "Hello, World!\n";
print $fh "This is a test.\n";

close($fh);

Open file for appending

open(my $fh, '>>', 'log.txt') or die "Cannot open file: $!";

print $fh "Log entry: " . localtime() . "\n";

close($fh);

Open mode summary

ModeDescriptionIf the file existsIf the file does not exist
<ReadRead from the beginningReport error
>writeclear and writecreate new file
>>AppendAppend at the endCreate new file
+<Read and writeRead and write from the beginningReport errors
+>Read and writeClear and read and writeCreate new file
+>>read and write appendread and writecreate new file

Read file

Read line by line

open(my $fh, '<', 'data.txt') or die "Cannot open file: $!";

while (my $line = <$fh>) {
    chomp $line;  # 移除换行符
    print "$line\n";
}

close($fh);

Read the entire file into an array

open(my $fh, '<', 'data.txt') or die "Cannot open file: $!";

my @lines = <$fh>;  # 读取所有行
close($fh);

foreach my $line (@lines) {
    chomp $line;
    print "$line\n";
}

Read entire file into scalar

open(my $fh, '<', 'data.txt') or die "Cannot open file: $!";

# 方法 1:使用 local
local $/;
my $content = <$fh>;
close($fh);

print $content;

# 方法 2:使用 File::Slurp
use File::Slurp;
my $content2 = read_file('data.txt');

Read a fixed number of bytes

open(my $fh, '<', 'data.txt') or die "Cannot open file: $!";

my $buffer;
my $bytes_read = read($fh, $buffer, 1024);  # 读取 1024 字节

print "Read $bytes_read bytes\n";
print $buffer;

close($fh);

Using sysread and syswrite

open(my $fh, '<', 'data.txt') or die "Cannot open file: $!";

my $buffer;
my $bytes_read = sysread($fh, $buffer, 256);

print "Read $bytes_read bytes using sysread\n";

close($fh);

Write to file

Write text

open(my $fh, '>', 'output.txt') or die "Cannot open file: $!";

print $fh "Line 1\n";
print $fh "Line 2\n";
print $fh "Line 3\n";

close($fh);

Use say to wrap lines automatically (Perl 5.10+)

use v5.10;

open(my $fh, '>', 'output.txt') or die "Cannot open file: $!";

say $fh "Line 1";
say $fh "Line 2";
say $fh "Line 3";

close($fh);

Formatted writing

open(my $fh, '>', 'report.txt') or die "Cannot open file: $!";

printf $fh "%-20s %10s %10s\n", "Name", "Age", "Score";
printf $fh "%-20s %10d %10d\n", "Alice", 25, 95;
printf $fh "%-20s %10d %10d\n", "Bob", 30, 88;

close($fh);

Use syswrite

open(my $fh, '>', 'output.txt') or die "Cannot open file: $!";

my $data = "Hello, World!";
my $bytes_written = syswrite($fh, $data);

print "Wrote $bytes_written bytes\n";

close($fh);

Append writing

open(my $fh, '>>', 'log.txt') or die "Cannot open file: $!";

my $timestamp = localtime();
print $fh "[$timestamp] Log message\n";

close($fh);

File test

Basic file test

my $file = 'test.txt';

if (-e $file) {
    print "File exists\n";
}

if (-f $file) {
    print "Is a regular file\n";
}

if (-d $file) {
    print "Is a directory\n";
}

if (-r $file) {
    print "Is readable\n";
}

if (-w $file) {
    print "Is writable\n";
}

if (-x $file) {
    print "Is executable\n";
}

File size and time

my $file = 'test.txt';

my $size = -s $file;
print "File size: $size bytes\n";

my $mtime = -M $file;
print "Modified $mtime days ago\n";

my $atime = -A $file;
print "Accessed $atime days ago\n";

my $ctime = -C $file;
print "Changed $ctime days ago\n";

File permissions

my $file = 'test.txt';

printf "Owner: %04o\n", (stat($file))[2] & 0777;

if (-r $file && -w $file) {
    print "Readable and writable\n";
}

if (-R $file) {
    print "Real user can read\n";
}

if (-W $file) {
    print "Real user can write\n";
}

File Type

my $file = 'test.txt';

if (-f $file) { print "Regular file\n"; }
if (-d $file) { print "Directory\n"; }
if (-l $file) { print "Symbolic link\n"; }
if (-p $file) { print "Named pipe\n"; }
if (-S $file) { print "Socket\n"; }
if (-b $file) { print "Block special file\n"; }
if (-c $file) { print "Character special file\n"; }

File and directory operations

Delete files

# 删除单个文件
unlink 'file.txt' or warn "Cannot delete file: $!";

# 删除多个文件
my @files = ('file1.txt', 'file2.txt', 'file3.txt');
my $count = unlink @files;
print "Deleted $count files\n";

Rename file

rename('old.txt', 'new.txt') or die "Cannot rename: $!";

Copy files

# 方法 1:使用 File::Copy
use File::Copy;

copy('source.txt', 'destination.txt') or die "Cannot copy: $!";

# 方法 2:手动复制
open(my $in, '<', 'source.txt') or die "Cannot open source: $!";
open(my $out, '>', 'destination.txt') or die "Cannot open destination: $!";

while (my $line = <$in>) {
    print $out $line;
}

close($in);
close($out);

Move files

# 使用 File::Copy
use File::Copy;

move('source.txt', 'destination.txt') or die "Cannot move: $!";

# 或使用 rename
rename('source.txt', 'destination.txt') or die "Cannot move: $!";

Get file information

my $file = 'test.txt';

my @stats = stat($file);

my $dev = $stats[0];   # 设备号
my $ino = $stats[1];   # inode 号
my $mode = $stats[2];  # 文件模式
my $nlink = $stats[3]; # 硬链接数
my $uid = $stats[4];   # 用户 ID
my $gid = $stats[5];   # 组 ID
my $rdev = $stats[6];  # 特殊设备号
my $size = $stats[7];  # 文件大小
my $atime = $stats[8]; # 访问时间
my $mtime = $stats[9]; # 修改时间
my $ctime = $stats[10]; # 改变时间
my $blksize = $stats[11]; # 块大小
my $blocks = $stats[12]; # 块数量

printf "File: $file\n";
printf "Size: %d bytes\n", $size;
printf "Modified: %s\n", scalar localtime($mtime);
printf "Permissions: %04o\n", $mode & 0777;

Binary file operations

Read binary file

open(my $fh, '<:raw', 'binary.dat') or die "Cannot open file: $!";

binmode($fh);

my $buffer;
my $bytes_read = read($fh, $buffer, 1024);

print "Read $bytes_read bytes\n";

close($fh);

Write binary file

open(my $fh, '>:raw', 'output.dat') or die "Cannot open file: $!";

binmode($fh);

my $data = pack('C*', 0x01, 0x02, 0x03, 0x04);
print $fh $data;

close($fh);

Use pack and unpack

# 写入二进制数据
open(my $fh, '>:raw', 'data.dat') or die "Cannot open file: $!";

my $header = pack('A4LL', 'TEST', 12345, 67890);
print $fh $header;

close($fh);

# 读取二进制数据
open(my $fh, '<:raw', 'data.dat') or die "Cannot open file: $!";

my $buffer;
read($fh, $buffer, 12);  # 读取 12 字节

my ($magic, $num1, $num2) = unpack('A4LL', $buffer);

print "Magic: $magic\n";
print "Number 1: $num1\n";
print "Number 2: $num2\n";

close($fh);

Practical example

Example 1: File statistics tool

#!/usr/bin/perl
use strict;
use warnings;

sub count_file_stats {
    my ($filename) = @_;
    
    open(my $fh, '<', $filename) or die "Cannot open $filename: $!";
    
    my $line_count = 0;
    my $word_count = 0;
    my $char_count = 0;
    
    while (my $line = <$fh>) {
        $line_count++;
        $char_count += length($line);
        
        my @words = split /\s+/, $line;
        $word_count += scalar @words;
    }
    
    close($fh);
    
    return {
        lines => $line_count,
        words => $word_count,
        chars => $char_count
    };
}

print "请输入文件名: ";
chomp(my $filename = <STDIN>);

if (-e $filename) {
    my $stats = count_file_stats($filename);
    
    print "=== 文件统计 ===\n";
    print "文件名: $filename\n";
    print "行数: $stats->{lines}\n";
    print "单词数: $stats->{words}\n";
    print "字符数: $stats->{chars}\n";
} else {
    print "文件不存在\n";
}

Example 2: Log file analyzer

#!/usr/bin/perl
use strict;
use warnings;

sub parse_log_line {
    my ($line) = @_;
    
    if ($line =~ /\[(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})\] \[(\w+)\] (.*)/) {
        return {
            timestamp => $1,
            level => $2,
            message => $3
        };
    }
    
    return undef;
}

sub analyze_log {
    my ($filename) = @_;
    
    open(my $fh, '<', $filename) or die "Cannot open $filename: $!";
    
    my %level_counts;
    my @errors;
    
    while (my $line = <$fh>) {
        my $entry = parse_log_line($line);
        
        if ($entry) {
            $level_counts{$entry->{level}}++;
            
            if ($entry->{level} eq 'ERROR') {
                push @errors, $entry;
            }
        }
    }
    
    close($fh);
    
    return {
        level_counts => \%level_counts,
        errors => \@errors
    };
}

my $log_file = 'app.log';

if (-e $log_file) {
    my $analysis = analyze_log($log_file);
    
    print "=== 日志分析 ===\n";
    print "日志级别统计:\n";
    
    foreach my $level (sort keys %{$analysis->{level_counts}}) {
        printf "  %s: %d\n", $level, $analysis->{level_counts}{$level};
    }
    
    print "\n错误日志:\n";
    foreach my $error (@{$analysis->{errors}}) {
        printf "  [%s] %s\n", $error->{timestamp}, $error->{message};
    }
} else {
    print "日志文件不存在\n";
}

Example 3: CSV file processing

#!/usr/bin/perl
use strict;
use warnings;
use Text::CSV;

my $csv = Text::CSV->new({ binary => 1, auto_diag => 1 });

# 读取 CSV
open(my $fh, '<', 'data.csv') or die "Cannot open file: $!";

my @headers = @{$csv->getline($fh)};
my @rows;

while (my $row = $csv->getline($fh)) {
    my %data;
    @data{@headers} = @$row;
    push @rows, \%data;
}

close($fh);

# 显示数据
print "=== CSV 数据 ===\n";
foreach my $row (@rows) {
    print "-" x 40 . "\n";
    foreach my $header (@headers) {
        printf "%-15s: %s\n", $header, $row->{$header};
    }
}

# 写入 CSV
open(my $out, '>', 'output.csv') or die "Cannot create file: $!";
$csv->print($out, \@headers);

foreach my $row (@rows) {
    my @values = map { $row->{$_} } @headers;
    $csv->print($out, \@values);
}

close($out);

Summary

In this chapter, we learned about Perl’s file operations:

  1. ✅ Open and close files
  2. ✅ Read files (line by line, whole, binary)
  3. ✅Write files
  4. ✅ File test
  5. ✅ File and directory operations
  6. ✅ Binary file operations

Next, we'll learn about Perl Directory Operations.