有这个片段:
my $file = "input.txt"; # let's assume that this is an ascii file
my $size1 = -s $file;
print "$size1\n";
$size2 = 0;
open F, $file;
$size2 += length($_) while (<F>);
close F;
print "$size2\n";
何时可以断言$size1
等于$size2
是真的?
答案 0 :(得分:3)
您不能,因为输入图层可能会对输入行进行一些转换,例如将crlf
更改为cr
,这可能会更改该行的长度。
此外,length $line
计算$line
中多少字符,在多字节编码中,如@choroba给出的示例,一个字符可能占用多个字节。
有关详细信息,请参阅perlio
。
答案 1 :(得分:3)
如果您没有指定支持多字节字符的编码,则应该保留。否则,结果可能会有所不同:
$ cat 1.txt
žluťoučký kůň
$ perl -E 'say -s "1.txt";
open my $FH, "<:utf8", "1.txt";
my $f = do { local $/; <$FH> };
say length $f;'
20
14
答案 2 :(得分:2)
不,正如Lee Duhem
所说,由于Perl的行尾处理,这两个数字可能不同,或者因为length
报告中字符串的大小字符,如果文本中有任何宽字符,则会抛出数字。
但tell
函数会报告您已阅读的确切位置(以字节为单位),因此等同于 数字的程序保证匹配是这个
use strict;
use warnings;
my $file = 'input.txt';
my $size1 = -s $file;
print "$size1\n";
open my $fh, '<', $file or die $!;
my $size2 = 0;
while (<$fh>) {
$size2 = tell $fh;
}
close $fh;
print "$size2\n";
请注意使用use strict
和use warnings
,词汇文件句柄,open
的三参数形式,以及检查它是否成功。所有这些都是Perl程序的最佳实践,应该在你写的所有中使用
答案 3 :(得分:1)
您只是缺少binmode(F);
或:raw
IO层。这些导致Perl完全按照磁盘上显示的方式返回文件。没有行结束翻译。不解码字符编码。
open(my $fh, '<:raw', $file)
or die "open $file: $!\n");
然后你的代码工作正常。
my $size = 0;
$size += length while <$fh>;
这不是特别好,因为它可以立即读取整个文件的二进制文件。因此,让我们改为读取固定大小的块。
local $/ = \(64*1024);
my $size = 0;
$size += length while <$fh>;
这与使用read
基本相同,sysread
一次读取4K或8K(在较新的Perls中)。阅读比一次阅读更有效,我们可以使用my $size = 0;
while (my $bytes_read = sysread($fh, my $buf, 64*1024)) {
$size += $bytes_read;
}
来做到这一点。
use Fcntl qw( SEEK_END );
my $size = sysseek($fh, 0, SEEK_END);
但是阅读整个文件很愚蠢。你可以找到文件的末尾。
-s
但话又说回来,你也可以使用my $size = -s $fh;
。
{{1}}