在Perl 6中如何向文件追加内容?

7
我尝试了这个方法和其他一些方法,但每次都会截断文件:
my $file = 'primes.txt';
sub MAIN ( Int:D $low, Int:D $high where * >= $low ) {
    unless my $fh = open $file, :w, :append {
        die "Could not open '$file': {$fh.exception}";
    }

    for $low .. $high {
        $fh.put: $_ if .is-prime;
    }
}

更改为open $file, :a似乎也会截断文件。 这是在macOS上的2018.04。

2
文档中得知::w:mode<wo>,:create,:truncate的指定方式相同。因此行为完全符合规范。当您指定:w时,将放弃使用:append而选择使用:truncate。请改用:a代替:w :append - jjmerelo
1
我看到:a也有同样的问题。 - brian d foy
3
如果 Perl 6 将忽略你传递的某些内容,它应该警告你。 - brian d foy
1
抱歉,我没有看到问题(使用2018.04)。perl6 append-file.p6 1 20,文件包含:2 3 5 7 11 13 17 19 然后运行 perl6 append-file.p6 200 300,它会追加以下内容:19 211 223 227 229 233 239 241 251 257 263 269 271 277 281 283 293 (这里包括了19)。至于忽略某些东西,那是完全不同的事情。也许引发异常或警告会导致更多的混乱。 - jjmerelo
2
普通的 open $file, :a 不应该截断文件,并且在我上个月构建的Perl6版本上没有截断(尽管我使用的是Windows而不是MacOS)。 - Christoph
2个回答

8

Perl6的&open语义基于POSIX,具体映射如下:

:mode<ro>  --> O_RDONLY
:mode<wo>  --> O_WRONLY
:mode<rw>  --> O_RDWR
:create    --> O_CREAT
:append    --> O_APPEND
:truncate  --> O_TRUNC
:exclusive --> O_EXCL

为了方便起见,我们提供以下快捷方式:

:r      --> :mode<ro>
:w      --> :mode<wo>, :create, :truncate
:x      --> :mode<wo>, :create, :exclusive
:a      --> :mode<wo>, :create, :append
:update --> :mode<rw>
:rw     --> :mode<rw>, :create
:rx     --> :mode<rw>, :create, :exclusive
:ra     --> :mode<rw>, :create, :append

并非所有被Rakudo支持的平台(例如Windows、JVM,甚至POSIX本身)都支持所有可能的模式和标志的组合,因此仅上述组合才保证按预期方式运行(或者至少应该是这样)。

简而言之,在我的Windows机器上,一个简单的:a绝对应该能够做到你想要的事情。如果在MacOS上真的会截断,我会认为这是一个bug。


3

使用:mode<wo>, :append可以工作,尽管当大多数人看到:a时,这不会是他们首选的方法:

my $file = 'primes.txt';
sub MAIN ( Int:D $low, Int:D $high where * >= $low ) {
    unless my $fh = open $file, :mode<wo>, :append {
        die "Could not open '$file': {$fh.exception}";
        }

    for $low .. $high {
        $fh.put: $_ if .is-prime;
        }

    $fh.close;
    }

问题在于Perl 6往往会默默忽略命名参数。而且看起来roast/open.t并没有通过用户界面真正测试这些内容。它执行各种技巧,这些技巧可能需要进行重构。

1
请注意:虽然根据 :mode<wo>:append 的文档定义,它们的组合对我来说是有意义的,但我注意到 open例程的文档中说它调用了 IO::Handleopen 方法,而后者的文档则表示,“除了上面列出的模式组合之外的其他模式组合可能会起作用,也可能会导致宇宙崩溃”。组合 :mode<wo>, :append 并没有出现在该句话上面。因此,它今天可能有效,但明天可能无效。 - raiph
1
@raiph 那个链接是关于方法的,但这里的 open 不是子例程吗? 子例程不关心额外的命名参数(与方法不同)吗? - Christopher Bottoms
1
@ChristopherBottoms:&open 的实现方式是 multi sub open(IO() $path, |c) { IO::Handle.new(:$path).open(|c) },通过将参数传递给该方法... - Christoph
2
@raiph:P6开放模式基于POSIX语义;问题在于这些语义在Windows和JVM上几乎完全支持,但不是全部支持。 - Christoph
1
嗨Brian。假设你最后的评论是对我的回应...确实。我认为这种区别非常重要。目前还不清楚您是否不同意或误解或不关心接口一致性原则(Larry / Perl 6设计事物)或Rakudo当前缺乏有关未使用命名参数的警告(tuit / 实现缺陷事物),或者重要的是要区分它们。接口一致性经常受到不当抨击。您关于“问题”的评论似乎指责原则,而不是Rakudo,或者不关心区别。 - raiph
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接