输入和输出

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

读取文件

读取文件内容的一种方法是通过带有 :r(读取)文件模式选项的 open 函数打开文件,并吞噬内容:

  1. my $fh = open "testfile", :r;
  2. my $contents = $fh.slurp;
  3. $fh.close;

这里我们使用 IO::Handle 对象上的 close 方法显式地关闭文件句柄。这是一种非常传统的读取文件内容的方法。但是,同样的事情可像这样更容易和更清楚地完成:

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

通过将 IO 角色添加到文件名字符串中,我们实际上能够将字符串作为文件对象本身引用,从而直接吞噬其内容中。请注意,slurp 负责为你打开和关闭文件。

逐行读取

当然,我们也可以选择逐行读取文件。将排除新行分隔符(即 $*IN.nl-in)。

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

写文件

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

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

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

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

我们可以通过使用 spurt 在写入模式下打开文件,将数据写入文件并再次为我们关闭来简化此操作:

  1. spurt "testfile", "data and stuff\n";

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

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

要将格式化的字符串写入文件, 请使用 IO::Handleprintf 函数。

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

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

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

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

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

或者甚至在调用 spurt 时加上 :append 选项:

  1. spurt "testfile", "more data\n", :append;

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

复制和重命名文件

例程 copy, rename, 和 move 是可用的以避免低级别的系统命令。 在 copy, rename, 和 move 查看详情. 一些例子:

  1. my $filea = 'foo';
  2. my $fileb = 'foo.bak';
  3. my $filec = '/disk1/foo'; # note 'diskN' is assumed to be a physical storage device
  4. copy $filea, $fileb; # overwrites $fileb if it exists
  5. copy $filea, $fileb, :createonly; # fails if $fileb exists
  6. rename $filea, 'new-foo'; # overwrites 'new-foo' if it exists
  7. rename $filea, 'new-foo', :createonly; # fails if 'new-foo' exists
  8. # use move when a system-level rename may not work
  9. move $fileb, '/disk2/foo'; # overwrites '/disk2/foo' if it exists
  10. move $fileb, '/disk2/foo', :createonly; # fails if '/disk2/foo' exists

检查文件和目录

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

  1. if "nonexistent_file".IO.e {
  2. say "file exists";
  3. }
  4. else {
  5. say "file doesn't exist";
  6. }

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

  1. if "path/to/file".IO ~~ :e {
  2. say 'file exists';
  3. }
  4. my $file = "path/to/file";
  5. if $file.IO ~~ :e {
  6. say 'file exists';
  7. }

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

  1. say "testfile".IO.e; # OUTPUT: «True
  2. »
  3. say "lib".IO.e; # OUTPUT: «True
  4. »

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

  1. say "testfile".IO.d; # OUTPUT: «False
  2. »
  3. say "lib".IO.d; # OUTPUT: «True
  4. »

当我们通过文件测试方法 f 检查路径是否是文件时,结果自然会反过来:

  1. say "testfile".IO.f; # OUTPUT: «True
  2. »
  3. say "lib".IO.f; # OUTPUT: «False
  4. »

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

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

更多方法和详细信息请查看 IO::Path.

获取目录列表

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

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

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

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

创建和移除目录

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

  1. mkdir "newdir";

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

  1. mkdir "newdir" or die "$!";

使用 rmdir 来移除*空*目录:

  1. rmdir "newdir" or die "$!";