使用Perl如何获取文件大小(以兆字节为单位)?

17

我想获取文件在磁盘上的大小,以兆字节为单位。使用-s运算符可以让我得到以字节为单位的大小,但假设将其除以一个魔术数字是不明智的:

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

我应该使用只读变量来定义1024,还是有一种编程方式可以获取一个千字节的字节数?

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

8个回答

33

如果您想要避免魔数,可以尝试使用CPAN模块Number::Bytes::Human

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

1
刚刚发现它还可以将人类可读的字符串解析回字节! - Matthew Lock

11

这是一个旧问题,并已经得到了正确的答案,但是如果您的程序受限于核心模块并且无法使用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和...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,也要查看源代码以了解需要注意的所有内容。

7

当然,您可以创建一个用于计算这个值的函数。在这种情况下,这是比创建常量更好的解决方案。

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

不需要常量。将1024更改为某种变量/常量并不会使此代码更易读。


4

其实,一个兆字节里面不是有1024个字节,而是有1024个千字节(KB),每个千字节里面有1024个字节。

话虽如此,但是1024是一个安全的“魔数”,在你编写的程序中,这个数字永远不会改变,因为它适用于任何系统。


2
跟市场部门沟通一下吧,他们有不同的看法(在我看来是错误的,但嘿,他们有更多的钱)。 - lexu
更新了问题。现在还很早,请原谅我把千字节错认为兆字节了 :) - cowgod
即使魔数是“安全的”,使用命名常量使您的代码更易读。考虑物理常数如G、c,或数学常数如pi或e。当然,它们在我们的宇宙中永远不会改变,但如果使用名称而不是值,您的表达式将更易读。 - Adam Bellaire
2
只需使用Number::Bytes::Human模块即可完成此操作。比自己编写代码容易得多,也更易读。 - jrockway
1
在那个时候,我认为使用正确的千兆字节和吉比字节的定义非常重要(http://en.wikipedia.org/wiki/GiB)。作为两个不同的实体,我们不应该担心这个问题。如果需要,您可以随时轻松地从千兆转换为吉比。 - user54650
显示剩余3条评论

4

我建议将此内容读入变量,而不是使用魔术数字。即使像一个兆字节中的字节数这样的魔术数字不会改变,使用良好命名的常量也是一种良好的习惯,因为它可以使您的代码更易读。这可以让其他人立即了解您的意图。


1

1) 你不想要1024。那只给你千字节。你需要1024*1024,或1048576。

2) 为什么用一个神奇的数字除法是个坏主意?就像兆字节中的字节数永远不会改变一样。不要过度思考。


1

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

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

然而,有意义的做法可能是声明非明显的东西,比如“$megabyte = 1024 * 1024”,因为这比1048576更易读。


1

由于 -s 操作符以字节为单位返回文件大小,因此您应该做类似以下的操作

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

如果需要一个四舍五入的数字,请使用int()函数。毕竟,在不久的将来,KB或MB的尺寸也不会改变:)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接