【问题标题】:difference between -s and my implementation-s 和我的实现之间的区别
【发布时间】:2014-05-25 16:14:01
【问题描述】:

有这个sn-p:

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

【问题讨论】:

    标签: perl file loops


    【解决方案1】:

    如果您没有指定支持多字节字符的编码,它应该保留。否则,结果可能不同:

    $ 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
    

    【讨论】:

    • 根据谷歌的说法,“publish horse”
    • @Borodin: Yellow horse 是更好的翻译 :)
    【解决方案2】:

    你不能,因为输入层可能会对输入行进行一些转换,例如将crlf更改为cr,这可能会改变该行的长度。

    另外,length $line统计$line中有多少个字符,在多字节编码中,如@choroba给出的例子,一个字符可能占用多个字节。

    更多详情请参阅perlio

    【讨论】:

      【解决方案3】:

      不,正如Lee Duhem 所说,这两个数字可能不同,因为 Perl 的行尾处理,或者因为lengthcharacters 报告字符串的大小,这将如果文本中有任何宽字符,则将数字丢弃。

      但是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 程序的最佳实践,应该在您编写的所有内容中使用

      【讨论】:

      • Re“如果文本中有任何宽字符,它将抛出数字”,在 OP 的示例中,如果使用 -C-Mopen=...(目录或通过env var PERL5OPTS),或者如果使用了 env var PERLIO
      • @ikegami:谢谢。 (你的意思是直接?)
      • 是的,错字。 “直接,或通过环境变量PERL5OPTS”。
      【解决方案4】:

      您只是缺少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 基本相同,它一次读取 4K 或 8K(在较新的 Perls 中)。一次阅读更多内容对性能有好处,我们可以使用sysread 来做到这一点。

      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;
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-02-26
        • 2014-02-14
        • 2020-02-13
        • 2016-12-05
        • 2023-03-03
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多