Как получить размер файла в мегабайтах с помощью Perl? - PullRequest
13 голосов
/ 04 февраля 2009

Я хочу получить размер файла на диске в мегабайтах. Использование оператора -s дает мне размер в байтах, но я собираюсь предположить, что деление этого на магическое число - плохая идея:

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

Должен ли я просто использовать переменную только для чтения, чтобы определить 1024, или есть программный способ получения количества байтов в килобайтах?

РЕДАКТИРОВАТЬ: Обновлен неправильный расчет.

Ответы [ 8 ]

30 голосов
/ 04 февраля 2009

Если вы хотите избежать магических чисел, попробуйте модуль CPAN Number :: Bytes :: Human .

use Number::Bytes::Human qw(format_bytes);
my $size = format_bytes(-s $file); # 4.5M
6 голосов
/ 05 февраля 2009

Конечно, вы можете создать функцию для вычисления этого. Это лучшее решение, чем создание констант в этом случае.

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

Нет необходимости в константах. Изменение 1024 на некоторую переменную / константу не сделает этот код более читабельным.

4 голосов
/ 16 марта 2014

Это старый вопрос, и на него уже правильно ответили, но на случай, если ваша программа ограничена основными модулями, и вы не можете использовать Number :: Bytes :: Human здесь у вас есть несколько других варианты у меня были собраны со временем. Я сохранил их также потому, что каждый из них использует свой подход Perl и является хорошим примером для TIMTOWTDI :

  • пример 1: использует состояние, чтобы избежать повторной инициализации переменной каждый раз (перед perl 5.16 вам нужно использовать состояние объекта или 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 Гб = 1024 Мб, 1 Мб = 1024 Кб и 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, взгляните на исходный код, чтобы увидеть все, что вам нужно знать.

4 голосов
/ 04 февраля 2009

Я бы прочитал это в переменную, а не использовал бы магическое число. Даже если магические числа не будут меняться, например, количество байтов в мегабайте, использование константы с хорошим именем является хорошей практикой, поскольку делает ваш код более читабельным. Всем сразу становится ясно, каково ваше намерение.

4 голосов
/ 04 февраля 2009

Ну, в мегабайтах не 1024 байта, в K 1024 байта, а в мег 1024 K ...

Тем не менее, 1024 - это безопасное "волшебное" число, которое никогда не изменится ни в одной системе, в которой вы можете ожидать, что ваша программа будет работать.

1 голос
/ 04 февраля 2009

Поскольку оператор -s возвращает размер файла в байтах, вы, вероятно, должны делать что-то вроде

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

и используйте int (), если вам нужна круглая фигура. Не похоже, что размеры КБ или МБ изменятся в ближайшее время:)

1 голос
/ 04 февраля 2009

Не поймите меня неправильно, но: я думаю, что объявление 1024 как магической переменной заходит слишком далеко, это немного похоже на "$ ONE = 1; $ TWO = 2;" и т.д.

Килобайт был ошибочно объявлен как 1024 байта более 20 лет, и я серьезно сомневаюсь, что производители операционных систем когда-либо исправят эту ошибку и изменит ее на 1000.

Что может иметь смысл, так это объявлять неочевидные вещи, такие как «$ megabyte = 1024 * 1024», поскольку они более читабельны, чем 1048576.

1 голос
/ 04 февраля 2009

1) Вы не хотите 1024. Это дает вам килобайт. Вы хотите 1024 * 1024 или 1048576.

2) Почему деление на магическое число было бы плохой идеей? Это не так, как число байтов в мегабайте когда-либо изменится. Не слишком задумывайся над вещами.

...