当前位置: 首页 > 文档资料 > Perl6 入门指导 >

第四章 Perl6 文件操作

优质
小牛编辑
119浏览
2023-12-01

译注:
在原文标题后加上小括号以表示其为方法名,以与一般标题加以区别。

exit()

在学习怎么处理文件之前,我们先来了解一些实用的函数。

exit()能够使程序在任何调用它的地方退出,即无需运行到最后一行就结束。

tutorial/files/exit.p6

#!/usr/bin/env perl6
use v6;

say "hello";

exit;

say "world";

warn()

warn()能够将一条错误信息打印至标准错误流(STDERR),且程序将保持运行,不会因此而退出。

tutorial/files/warn.p6

#!/usr/bin/env perl6
use v6;

warn "This is a warning";

say "Hello World";

译注:
在控制台时将打印出

This is a warning
  in block <unit> at <unknown file> line 1

die()

die()将打印一条信息到标准错误流并终止程序的运行。

tutorial/files/die.p6

#!/usr/bin/env perl6
use v6;

say "Before calling die";

die "This will kill the script";

say "This will not show up";

Twigils与特殊变量

译注:
twigil一词只出现在Perl语言的特殊语境下,是一种能够表示变量名作用域的符号。
关于twigil的更多细节请参见Twigils

Perl6中存在大量的特殊变量,为了将其与常规的变量区分开来,我们为这些特殊变量加上一种称作twigil的二级前缀。

通常情况下,用户声明的变量前面会加有一种叫做sigil的前缀,如$@以及%等。

系统变量在sigil与变量名之间也有一个特殊的字符(*)。

例如:

  • $*PROGRAM-NAME:当前运行脚本的相对路径
  • $*PROGRAM:当前运行脚本的文件名称
  • $*CWD:当前工作路径
  • $*IN:标准输入流(STDIN),你可以使用$*IN.get来读取其中的一行
  • $*PID:当前进程PID
  • $*EXECUTABLE-NAME:运行当前脚本的二进制文件名称
  • $*EXECUTABLE:运行当前脚本的二进制文件的绝对路径
  • $*TMPDIR:用于存放临时文件的绝对路径

你可以在S28中了解到更多相关信息。

读取文件

与使用其他高级语言时一样,人们需要打开一个文件并对其进行读写。Perl6中可以使用IO中的方法open()来打开一个文件。

open()能够接收多个参数,其中文件名读写模式两者比较重要。如果想读取文件那么模式需要为:r

文件打开成功后会返回一个存放在标量中的文件句柄(handler),如果失败则抛出异常。

译注:
原文中作者说失败会返回undef,此说法已经过时。

$fh = open $filename, :r

一旦我们拥有了打开后的文件句柄,就可以使用方法$fh.get来读取给定文件里的一行。

我们可以反复使用get()来从文件中读取更多内容,然而有其他方法能够更好地做到这一点。

S32-setting-library/IO.pod中能够找到Perl6的所有IO规范。

tutorial/files/read_one_line.p6

#!/usr/bin/env perl6
use v6;

my $filename = $*PROGRAM-NAME;

my $fh = open $filename;
my $line = $fh.get;
say $line;

使用get()读取所有行

tutorial/files/read_file_line_by_line.p6

#!/usr/bin/env perl6
use v6;

my $filename = $*PROGRAM-NAME;

my $fh = open $filename;
while (defined my $line = $fh.get) {
    say $line;
}

逐行读取文件

tutorial/files/read_file.p6

#!/usr/bin/env perl6
use v6;

my $filename = $*PROGRAM-NAME;

my $fh = open $filename;
for $fh.lines -> $line {
    say $line;
}

lines()方法能够返回文件中的前几行(由参数控制)或者所有行(默认)。在上述代码中,其返回一个懒加载的列表,然后我们再使用for循环将其中的内容逐条输出。

此脚本与unix系统中cat命令的功能相近。

写文件

若希望对文件进行写操作,我们首先应该通过写模式:w打开文件。同样,打开成功后我们将获得一个文件句柄。

可以对文件句柄(IO句柄)调用一些常规方法如print()say()或者printf()

tutorial/files/write_file.p6

#!/usr/bin/env perl6
use v6;

my $filename = "temp.txt";

my $fh = open $filename, :w;
$fh.say("hello world"); # 成功则返回Ture
$fh.close; # 成功则返回Ture

文件模式

:r只读模式
:w只写模式
:rw读写模式
:a追加模式

译注:
原文中作者遗漏了读写模式。
更多关于文件/编码/新行模式的信息请参见IO

slurp()与spurt()

Perl6中内置了一种读取文件的模式,用来“啜食”(slurp)文件中的内容,即读取文件中的全部信息到一个标量中。

tutorial/files/slurp_file.p6

#!/usr/bin/env perl6
use v6;

my $filename = $*PROGRAM-NAME;

my $data = slurp $filename;
say $data.bytes;

译注:
Perl6中同样有方法将内容“喷射”(spurt)进文件中。

my $newdata = "New scores:
Paul 10
Paulie 9
Paulo 11";

spurt "newdatafile.txt", $newdata;

将文件逐行读取至数组

我们还没有学习有关数组的知识,在此之前我可以先告诉你,如果将slurp()调用的返回值放进一个数组,那么整个文件内容将变成数组中第一个也是唯一的一个元素。

如果我们希望将文件中的每一行都作为一个元素依次放进数组中呢?

lines()函数可以做到这一点。

tutorial/files/read_file_into_array.p6

#!/usr/bin/env perl6
use v6;

my $filename = $*PROGRAM-NAME;

# 将文件中全部内容读取至数组的第一个元素
my @content = slurp $filename;
say @content.elems;

# 读取文件中全部内容,每一行作为数组中的一个元素
my @rows = lines $filename.IO;
say @rows.elems;

练习:利用文件IO计算其中数字的和

创建一个文件,其中的每一行有一个数字。

打印这些数字的和。

tutorial/numbers.txt

3
8
19
-7
13

结果为36。

修改程序,打印出平均值、最小值和最大值。

同时思考如何计算中值与标准差。

答案:利用文件IO计算其中数字的和

tutorial/files/statistics.p6

#!/usr/bin/env perl6
use v6;

my $filename = 'examples/numbers.txt';

my $total;
my $count;
my $min;
my $max;

if (my $fh = open $filename, :r) {
    for $fh.lines -> $line {
        if (not $count) {
            $min = $max = $line;
        }
        $total += $line;
        if ($min > $line) {
            $min = $line;
        }
        if ($max < $line) {
            $max = $line;
        }
        $count++;
    }
    my $average = $total / $count;
    say "Total: $total, Count: $count Average: $average Min: $min Max: $max";
} else {
    say "Could not open '$filename'";
}

# 思考:答案有一个小瑕疵——文件中没有任何值时该怎么办?