【问题标题】:How do I get the size of a file in megabytes using Perl?如何使用 Perl 获取文件的大小(以兆字节为单位)?
【发布时间】:2010-10-05 10:28:31
【问题描述】:

我想获取磁盘上文件的大小(以 MB 为单位)。使用-s 运算符可以得到以字节为单位的大小,但我假设将其除以一个幻数是一个坏主意:

my $size_in_mb = (-s $fh) / (1024 * 1024);

我应该只使用只读变量来定义 1024 还是有编程方式来获取以千字节为单位的字节数?

编辑:更新了不正确的计算。

【问题讨论】:

    标签: perl file-io filesize magic-numbers


    【解决方案1】:

    嗯,一个兆不是 1024 个字节,一个 K 是 1024 个字节,一个兆是 1024 K...

    也就是说,1024 是一个安全的“神奇”数字,在您可以期望程序运行的任何系统中都不会改变。

    【讨论】:

    • 类似的情况是在米和公里之间进行转换......你会因为包含 1000 的“神奇”因子而感到难过吗?这是一个永远不会改变的直接单位转换。
    • 与营销人员交谈 .. 他们有不同的意见(恕我直言,但嘿,他们有更多的钱)
    • 更新了问题。现在还早,所以请原谅我将千字节误认为兆字节。 :)
    • 只需使用 Number::Bytes::Human 模块即可。比自己做要容易得多,而且可读性更强。
    • 在这一点上,我认为正确定义 gigabyte 和 gibibyte (en.wikipedia.org/wiki/GiB) 应该是至关重要的。作为两个独立的实体,我们不应该担心这一点。如果需要,您可以随时轻松地从 giga 转换为 gibi。
    【解决方案2】:

    1) 你不想要 1024。这会给你千字节。你想要 1024*1024 或 1048576。

    2) 为什么除以幻数是个坏主意?它不像一兆字节中的字节数会永远改变。不要想太多。

    【讨论】:

      【解决方案3】:

      不要误会我的意思,但是:我认为将 1024 声明为魔术变量有点过头了,这有点像“$ONE = 1; $TWO = 2;”等等

      20 多年来,千字节一直被错误地声明为 1024 字节,我严重怀疑操作系统制造商是否会纠正该错误并将其更改为 1000。

      但有意义的是声明不明显的东西,例如“$megabyte = 1024 * 1024”,因为它比 1048576 更具可读性。

      【讨论】:

        【解决方案4】:

        由于 -s 运算符以字节为单位返回文件大小,因此您可能应该执行类似

        的操作
        my $size_in_mb = (-s $fh) / (1024 * 1024);
        

        如果你需要一个圆形,请使用 int()。这不像 KB 或 MB 的尺寸会在不久的将来随时改变 :)

        【讨论】:

          【解决方案5】:

          我会将其读入变量而不是使用幻数。即使幻数不会改变,例如 1 MB 中的字节数,使用命名良好的常量也是一种很好的做法,因为它使您的代码更具可读性。它让其他人立即明白你的意图是什么。

          【讨论】:

            【解决方案6】:

            如果您想避免使用幻数,请尝试使用 CPAN 模块 Number::Bytes::Human

            use Number::Bytes::Human qw(format_bytes);
            my $size = format_bytes(-s $file); # 4.5M
            

            【讨论】:

            • 刚刚发现它还可以将人类可读的字符串解析回字节!
            【解决方案7】:

            您当然可以创建一个函数来计算它。这比在这种情况下创建常量更好。

            sub size_in_mb {
                my $size_in_bytes = shift;
                return $size_in_bytes / (1024 * 1024);
            }
            

            不需要常量。将1024 更改为某种变量/常量不会使这段代码更具可读性。

            【讨论】:

              【解决方案8】:

              这是一个老问题,已经得到了正确的回答,但以防你的程序受限于核心模块并且你不能使用Number::Bytes::Human 这里你有几个其他的选项我已经收集了一段时间。我保留它们也是因为每个都使用不同的 Perl 方法,并且是 TIMTOWTDI 的一个很好的例子:

              • 示例 1:使用 state 避免每次都重新初始化变量(在 perl 5.16 之前您需要使用 feature state 或 perl -E)

              http://kba49.wordpress.com/2013/02/17/format-file-sizes-human-readable-in-perl/

                  sub formatSize {
                      my $size = shift;
                      my $exp = 0;
              
                      state $units = [qw(B KB MB GB TB PB)];
              
                      for (@$units) {
                          last if $size < 1024;
                          $size /= 1024;
                          $exp++;
                      }
              
                      return wantarray ? ($size, $units->[$exp]) : sprintf("%.2f %s", $size, $units->[$exp]);
                  }
              
              • 示例 2:使用排序映射

              .

              sub scaledbytes {
              
                  # http://www.perlmonks.org/?node_id=378580
                  (sort { length $a <=> length $b 
                        } map { sprintf '%.3g%s', $_[0]/1024**$_->[1], $_->[0]
                              }[" bytes"=>0]
                              ,[KB=>1]
                              ,[MB=>2]
                              ,[GB=>3]
                              ,[TB=>4]
                              ,[PB=>5]
                              ,[EB=>6]
                  )[0]
                }
              
              • 示例 3:利用 1 Gb = 1024 Mb、1 Mb = 1024 Kb 和 1024 = 2 ** 10 的事实:

              .

              # http://www.perlmonks.org/?node_id=378544
              my $kb = 1024 * 1024; # set to 1 Gb
              
              my $mb = $kb >> 10;
              my $gb = $mb >> 10;
              
              print "$kb kb = $mb mb = $gb gb\n";
              __END__
              1048576 kb = 1024 mb = 1 gb
              
              • 示例4:使用++$n and ... until ..获取数组的索引

              .

              # http://www.perlmonks.org/?node_id=378542
              #! perl -slw
              use strict;
              
              sub scaleIt {
                  my( $size, $n ) =( shift, 0 );
                  ++$n and $size /= 1024 until $size < 1024;
                  return sprintf "%.2f %s",
                         $size, ( qw[ bytes KB MB GB ] )[ $n ];
              }
              
              my $size = -s $ARGV[ 0 ];
              
              print "$ARGV[ 0 ]: ", scaleIt $size;  
              

              即使您不能使用 Number::Bytes::Human,也请查看源代码以了解您需要注意的所有事项。

              【讨论】:

                猜你喜欢
                • 2012-02-17
                • 1970-01-01
                • 1970-01-01
                • 2010-10-08
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2013-02-01
                • 1970-01-01
                相关资源
                最近更新 更多