这里我们简要概述了与文件相关的输入/输出操作。详细信息可以在 IO 角色的文档中找到,以及 IO::HandleIO::Path 类型。

slurp

从文件读取§

读取文件内容的一种方法是通过 open 函数使用 :r(读取)文件模式选项打开文件,并吸入内容

my $fh = open "testfile":r;
my $contents = $fh.slurp;
$fh.close;

这里我们使用 IO::Handle 对象上的 close 方法显式地关闭文件句柄。这是读取文件内容的一种非常传统的方式。但是,可以使用以下更简单明了的方式来完成相同操作

my $contents = "testfile".IO.slurp;
# or in procedural form: 
$contents = slurp "testfile"

通过将 IO 角色添加到文件名字符串,我们实际上能够将字符串本身视为文件对象,从而直接吸入其内容。请注意,slurp 会为您处理打开和关闭文件。

逐行§

我们还可以选择逐行读取文件。换行符(例如,$*IN.nl-in)将被排除在外。

for 'huge-csv'.IO.lines -> $line {
    # Do something with $line 
}
 
# or if you'll be processing later 
my @lines = 'huge-csv'.IO.lines;

写入文件§

要将数据写入文件,我们同样可以选择使用传统的调用open函数的方法——这次使用:w(写入)选项——并将数据打印到文件中

my $fh = open "testfile":w;
$fh.print("data and stuff\n");
$fh.close;

或者等效地使用say,因此不再需要显式换行符

my $fh = open "testfile":w;
$fh.say("data and stuff");
$fh.close;

我们可以使用spurt来简化此操作,它将以写入模式打开文件,将数据写入文件并为我们关闭文件

spurt "testfile""data and stuff\n";

默认情况下,所有(文本)文件都以 UTF-8 编码写入,但是如果需要,可以通过:enc选项指定显式编码

spurt "testfile""latin1 text: äöüß"enc => "latin1";

要将格式化的字符串写入文件,请使用printf函数,该函数属于IO::Handle

my $fh = open "testfile":w;
$fh.printf("formatted data %04d\n"42);
$fh.close;

要追加到文件,请在显式打开文件句柄时指定:a选项,

my $fh = open "testfile":a;
$fh.print("more data\n");
$fh.close;

或者等效地使用say,因此不再需要显式换行符,

my $fh = open "testfile":a;
$fh.say("more data");
$fh.close;

或者更简单地使用spurt调用中的:append选项

spurt "testfile""more data\n":append;

要将二进制数据显式写入文件,请使用:bin选项打开它。然后,输入/输出操作将使用Buf类型而不是Str类型进行。

复制、重命名和删除文件§

copyrenamemoveunlink例程可用于避免使用低级系统命令。有关详细信息,请参阅copyrenamemoveunlink。以下是一些示例

my $filea = 'foo';
my $fileb = 'foo.bak';
my $filec = '/disk1/foo';
# note 'diskN' is assumed to be a physical storage device 
 
copy $filea$fileb;              # overwrites $fileb if it exists 
copy $filea$fileb:createonly# fails if $fileb exists 
 
rename $filea'new-foo';              # overwrites 'new-foo' if it exists 
rename $filea'new-foo':createonly# fails if 'new-foo' exists 
 
# use move when a system-level rename may not work 
move $fileb'/disk2/foo';              # overwrites '/disk2/foo' if it exists 
move $fileb'/disk2/foo':createonly# fails if '/disk2/foo' exists 
 
unlink $filea;
$fileb.IO.unlink;

两个unlink语句如果存在,则删除其参数,除非用户没有正确的权限这样做;在这种情况下,它会引发异常。

检查文件和目录§

IO::Handle对象使用e方法来测试文件或目录是否存在。

if "nonexistent_file".IO.e {
    say "file exists";
}
else {
    say "file doesn't exist";
}

也可以使用冒号对语法来实现相同的功能

if "path/to/file".IO ~~ :e {
    say 'file exists';
}
my $file = "path/to/file";
if $file.IO ~~ :e {
    say 'file exists';
}

类似于文件存在性检查,还可以检查路径是否为目录。例如,假设文件testfile和目录lib存在,我们将从存在性测试方法e获得相同的结果,即两者都存在

say "testfile".IO.e;  # OUTPUT: «True␤» 
say "lib".IO.e;       # OUTPUT: «True␤» 

但是,由于它们中只有一个是目录,因此目录测试方法d将给出不同的结果

say "testfile".IO.d;  # OUTPUT: «False␤» 
say "lib".IO.d;       # OUTPUT: «True␤» 

当然,如果我们通过文件测试方法f检查路径是否为文件,则情况就会发生变化

say "testfile".IO.f;  # OUTPUT: «True␤» 
say "lib".IO.f;       # OUTPUT: «False␤» 

还有其他方法可用于查询文件或目录,其中一些有用的方法是

my $f = "file";
 
say $f.IO.modified# return time of last file (or directory) change 
say $f.IO.accessed# return last time file (or directory) was read 
say $f.IO.s;        # return size of file (or directory inode) in bytes 

有关更多方法和详细信息,请参阅IO::Path

获取目录列表§

要列出当前目录的内容,请使用dir函数。它返回一个IO::Path对象的列表。

say dir;          # OUTPUT: «"/path/to/testfile".IO "/path/to/lib".IO␤»

要列出给定目录中的文件和目录,只需将路径作为参数传递给dir

say dir "/etc/";  # OUTPUT: «"/etc/ld.so.conf".IO "/etc/shadow".IO ....␤»

创建和删除目录§

要创建新目录,只需使用目录名称作为参数调用mkdir函数

mkdir "newdir";

该函数在成功时返回创建的目录的名称,在失败时返回Nil。因此,标准 Perl 惯用法按预期工作

mkdir "newdir" or die "$!";

使用rmdir删除目录

rmdir "newdir" or die "$!";