Diamond操作符(<>
)默认以文本模式工作,是否可以更改binmode
?似乎binmode
函数只接受句柄。
答案 0 :(得分:1)
二进制文件 在某些遗留系统上,可以称之为终端 复杂的(有些人会说破坏)I / O模型,文件不是文件 - 在 至少,不是与C标准I / O库有关。对这些旧的 其库(但不是内核)区分文本和文本的系统 二进制流,要使文件正常运行,你必须弯腰 向后避免讨厌的问题。在这种不恰当的系统上,插座 和管道已经以二进制模式打开,目前没有办法 把它关掉使用文件,您有更多选择。
另一种选择是在适当的句柄上使用“binmode”功能 在对它们进行常规I / O之前:
binmode(STDIN); binmode(STDOUT); while (<STDIN>) { print }
传递“sysopen”非标准标志选项也将打开该文件 支持它的那些系统上的二进制模式。这相当于 正常打开文件,然后在句柄上调用“binmode”。
sysopen(BINDAT, "records.data", O_RDWR | O_BINARY) || die "can't open records.data: $!";
现在您可以在该手柄上使用“read”和“print”而无需担心 非标准系统I / O库会破坏您的数据。这不是一个漂亮的 图片,但是,传统系统很少。 CP / M将与我们在一起直到 几天结束,之后。
在具有异国情调I / O系统的系统上,结果令人惊讶 足够的,甚至使用“sysread”和“syswrite”的无缓冲I / O可能会偷偷摸摸 背后的数据残割。
while (sysread(WHENCE, $buf, 1024)) { syswrite(WHITHER, $buf, length($buf)); }
根据运行时系统的变化,即使是这些调用也可能 首先需要“binmode”或“O_BINARY”。已知的系统没有这种系统 困难包括Unix,Mac OS,Plan 9和Inferno。
答案 1 :(得分:1)
<>
是一种便利。如果它只通过命令行中指定的文件名进行迭代,则可以使用$ARGV
中的while (<>)
来检测新文件的打开时间,binmode
,然后fseek
一开始。当然,这在重定向的情况下不起作用(控制台输入是另一个故事)。
一种解决方案是检测@ARGV
是否包含某些内容,并打开每个文件,默认为从STDIN
读取。使用迭代器进行的基本实现可能是:
#!/usr/bin/env perl
use strict;
use warnings;
use Carp qw( croak );
my $argv = sub {
@_ or return sub {
my $done;
sub {
$done and return;
$done = 1;
binmode STDIN;
\*STDIN;
}
}->();
my @argv = @_;
sub {
@argv or return;
my $file = shift @argv;
open my $fh, '<', $file
or croak "Cannot open '$file': $!";
binmode $fh;
$fh;
};
}->(@ARGV);
binmode STDOUT;
while (my $fh = $argv->()) {
while (my $line = <$fh>) {
print $line;
}
}
注意:
C:\...\Temp> xxd test.txt 00000000: 7468 6973 2069 7320 6120 7465 7374 0a0a this is a test..
没有binmode
:
C:\...\Temp> perl -e "print " test.txt | xxd 00000000: 7468 6973 2069 7320 6120 7465 7374 0d0a this is a test.. 00000010: 0d0a ..
使用上面的脚本:
C:\...\Temp> perl argv.pl test.txt | xxd 00000000: 7468 6973 2069 7320 6120 7465 7374 0a0a this is a test..
使用perl ... < test.txt | xxd
的相同结果,或perl ...