-s和我的实现之间的区别

时间:2014-04-11 13:16:55

标签: perl file loops

有这个片段:

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是真的?

4 个答案:

答案 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 strictuse 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}}