为什么重复打开、附加和关闭文本文件会导致行以相反的顺序写入?
Why does repeatedly opening, appending and closing a text file cause the lines to be written in reverse order?
为什么会出现以下 perl 代码:
for(open(my $fh, ">>", "test.txt")){
print $fh "one\n";
}
for(open(my $fh, ">>", "test.txt")){
print $fh "two\n";
}
for(open(my $fh, ">>", "test.txt")){
print $fh "three\n";
}
将以下内容写入test.txt?
three
two
one
为什么顺序变反了?我的理解是每个for
块在块退出时会自动关闭文件。这不应该导致 perl 在下一个块开始之前刷新所有缓冲区吗?我希望这段代码打开文件,写一行,关闭文件,然后再重复所有这些步骤两次。我错过了什么?
我用 Perl 5.26.1 测试了这个,运行ning 在 Ubuntu 18.04.3.
(是的,我知道只需将所有 print
语句放在同一个块中,我就可以轻松地以正确的顺序编写行。这不是这里的问题。我想了解 为什么会发生这种行为。)
为了奖金怪异,当我运行以下代码时:
for my $val (qw/ one two three /) {
for(open(my $fh, ">>", "test.txt")){
print $fh "$val\n";
}
}
它给我以下输出:
one
two
three
这段代码看起来在功能上应该与前面的代码相同。为什么它的行为不同?
这只是
的复杂版本
open(my $fh, ">>", "test.txt");
print $fh "one\n";
open(my $fh, ">>", "test.txt");
print $fh "two\n";
open(my $fh, ">>", "test.txt");
print $fh "three\n";
让我们做一些小改动,让事情更易读,更容易讨论:
open(my $fh1, ">>", "test.txt");
print $fh1 "one\n";
open(my $fh2, ">>", "test.txt");
print $fh2 "two\n";
open(my $fh3, ">>", "test.txt");
print $fh3 "three\n";
这是等价的,因为每个 my
都会创建一个新变量。
发生了什么事?
open(my $fh1, ">>", "test.txt"); # You create a file handle.
print $fh1 "one\n"; # You write to the file handle's buffer.
open(my $fh2, ">>", "test.txt"); # You create a file handle.
print $fh2 "two\n"; # You write to the file handle's buffer.
open(my $fh3, ">>", "test.txt"); # You create a file handle.
print $fh3 "three\n"; # You write to the file handle's buffer.
# Implicit close($fh3); # You close the file handle, flushing its buffer.
# Implicit close($fh2); # You close the file handle, flushing its buffer.
# Implicit close($fh1); # You close the file handle, flushing its buffer.
由于 Perl 不保证变量被销毁的顺序,您可以轻松地以任何顺序获得输出。
解决方案是在打印到句柄后刷新句柄($fh->flush;
,或$fh->autoflush(1);
),或者提前关闭句柄。
{ open(my $fh, ">>", "test.txt"); print $fh "one\n"; }
{ open(my $fh, ">>", "test.txt"); print $fh "two\n"; }
{ open(my $fh, ">>", "test.txt"); print $fh "three\n"; }
正如 ikegami 已经解释的那样,这种行为的原因在于变量可见性和存在的不同范围。
这是一个可视化的小例子:
#!/usr/bin/perl
use v5.16;
use warnings;
use experimental 'signatures';
package MyScalar;
sub TIESCALAR ($class, $val) {
my $self = $val;
bless $self, $class;
}
sub FETCH ($self) {
$$self;
}
sub DESTROY ($self) {
warn "destroying $$self\n";
}
package main;
for (tie my $val, 'MyScalar', 'first') {
say $val;
}
for (tie my $val, 'MyScalar', 'second') {
say $val;
}
for (tie my $val, 'MyScalar', 'third') {
say $val;
}
变量以不可预知的顺序销毁。这里的输出是:
destroying second
destroying first
destroying third
first
second
third
为什么会出现以下 perl 代码:
for(open(my $fh, ">>", "test.txt")){
print $fh "one\n";
}
for(open(my $fh, ">>", "test.txt")){
print $fh "two\n";
}
for(open(my $fh, ">>", "test.txt")){
print $fh "three\n";
}
将以下内容写入test.txt?
three
two
one
为什么顺序变反了?我的理解是每个for
块在块退出时会自动关闭文件。这不应该导致 perl 在下一个块开始之前刷新所有缓冲区吗?我希望这段代码打开文件,写一行,关闭文件,然后再重复所有这些步骤两次。我错过了什么?
我用 Perl 5.26.1 测试了这个,运行ning 在 Ubuntu 18.04.3.
(是的,我知道只需将所有 print
语句放在同一个块中,我就可以轻松地以正确的顺序编写行。这不是这里的问题。我想了解 为什么会发生这种行为。)
为了奖金怪异,当我运行以下代码时:
for my $val (qw/ one two three /) {
for(open(my $fh, ">>", "test.txt")){
print $fh "$val\n";
}
}
它给我以下输出:
one
two
three
这段代码看起来在功能上应该与前面的代码相同。为什么它的行为不同?
这只是
的复杂版本open(my $fh, ">>", "test.txt");
print $fh "one\n";
open(my $fh, ">>", "test.txt");
print $fh "two\n";
open(my $fh, ">>", "test.txt");
print $fh "three\n";
让我们做一些小改动,让事情更易读,更容易讨论:
open(my $fh1, ">>", "test.txt");
print $fh1 "one\n";
open(my $fh2, ">>", "test.txt");
print $fh2 "two\n";
open(my $fh3, ">>", "test.txt");
print $fh3 "three\n";
这是等价的,因为每个 my
都会创建一个新变量。
发生了什么事?
open(my $fh1, ">>", "test.txt"); # You create a file handle.
print $fh1 "one\n"; # You write to the file handle's buffer.
open(my $fh2, ">>", "test.txt"); # You create a file handle.
print $fh2 "two\n"; # You write to the file handle's buffer.
open(my $fh3, ">>", "test.txt"); # You create a file handle.
print $fh3 "three\n"; # You write to the file handle's buffer.
# Implicit close($fh3); # You close the file handle, flushing its buffer.
# Implicit close($fh2); # You close the file handle, flushing its buffer.
# Implicit close($fh1); # You close the file handle, flushing its buffer.
由于 Perl 不保证变量被销毁的顺序,您可以轻松地以任何顺序获得输出。
解决方案是在打印到句柄后刷新句柄($fh->flush;
,或$fh->autoflush(1);
),或者提前关闭句柄。
{ open(my $fh, ">>", "test.txt"); print $fh "one\n"; }
{ open(my $fh, ">>", "test.txt"); print $fh "two\n"; }
{ open(my $fh, ">>", "test.txt"); print $fh "three\n"; }
正如 ikegami 已经解释的那样,这种行为的原因在于变量可见性和存在的不同范围。 这是一个可视化的小例子:
#!/usr/bin/perl
use v5.16;
use warnings;
use experimental 'signatures';
package MyScalar;
sub TIESCALAR ($class, $val) {
my $self = $val;
bless $self, $class;
}
sub FETCH ($self) {
$$self;
}
sub DESTROY ($self) {
warn "destroying $$self\n";
}
package main;
for (tie my $val, 'MyScalar', 'first') {
say $val;
}
for (tie my $val, 'MyScalar', 'second') {
say $val;
}
for (tie my $val, 'MyScalar', 'third') {
say $val;
}
变量以不可预知的顺序销毁。这里的输出是:
destroying second
destroying first
destroying third
first
second
third