Perl 文件操作
打开和关闭文件
打开文件读取
perl
open(my $fh, '<', 'input.txt') or die "Cannot open file: $!";
while (my $line = <$fh>) {
print $line;
}
close($fh);打开文件写入
perl
open(my $fh, '>', 'output.txt') or die "Cannot open file: $!";
print $fh "Hello, World!\n";
print $fh "This is a test.\n";
close($fh);打开文件追加
perl
open(my $fh, '>>', 'log.txt') or die "Cannot open file: $!";
print $fh "Log entry: " . localtime() . "\n";
close($fh);打开模式总结
| 模式 | 说明 | 如果文件存在 | 如果文件不存在 |
|---|---|---|---|
< | 读取 | 从开头读取 | 报错 |
> | 写入 | 清空并写入 | 创建新文件 |
>> | 追加 | 在末尾追加 | 创建新文件 |
+< | 读写 | 从开头读写 | 报错 |
+> | 读写 | 清空并读写 | 创建新文件 |
+>> | 读写追加 | 读写 | 创建新文件 |
读取文件
逐行读取
perl
open(my $fh, '<', 'data.txt') or die "Cannot open file: $!";
while (my $line = <$fh>) {
chomp $line; # 移除换行符
print "$line\n";
}
close($fh);读取整个文件到数组
perl
open(my $fh, '<', 'data.txt') or die "Cannot open file: $!";
my @lines = <$fh>; # 读取所有行
close($fh);
foreach my $line (@lines) {
chomp $line;
print "$line\n";
}读取整个文件到标量
perl
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');读取固定字节数
perl
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);使用 sysread 和 syswrite
perl
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);写入文件
写入文本
perl
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);使用 say 自动换行(Perl 5.10+)
perl
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);格式化写入
perl
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);使用 syswrite
perl
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);追加写入
perl
open(my $fh, '>>', 'log.txt') or die "Cannot open file: $!";
my $timestamp = localtime();
print $fh "[$timestamp] Log message\n";
close($fh);文件测试
基本文件测试
perl
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";
}文件大小和时间
perl
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";文件权限
perl
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";
}文件类型
perl
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"; }文件和目录操作
删除文件
perl
# 删除单个文件
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";重命名文件
perl
rename('old.txt', 'new.txt') or die "Cannot rename: $!";复制文件
perl
# 方法 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);移动文件
perl
# 使用 File::Copy
use File::Copy;
move('source.txt', 'destination.txt') or die "Cannot move: $!";
# 或使用 rename
rename('source.txt', 'destination.txt') or die "Cannot move: $!";获取文件信息
perl
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;二进制文件操作
读取二进制文件
perl
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);写入二进制文件
perl
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);使用 pack 和 unpack
perl
# 写入二进制数据
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);实践示例
示例 1:文件统计工具
perl
#!/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";
}示例 2:日志文件分析器
perl
#!/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";
}示例 3:CSV 文件处理
perl
#!/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);小结
本章节学习了 Perl 的文件操作:
- ✅ 打开和关闭文件
- ✅ 读取文件(逐行、整体、二进制)
- ✅ 写入文件
- ✅ 文件测试
- ✅ 文件和目录操作
- ✅ 二进制文件操作
接下来,我们将学习 Perl 目录操作。