Есть ли более эффективный способ создания случайного файла на Perl?

Это мой первый Perl-скрипт. Когда-либо:

#!/usr/bin/perl

if ($#ARGV < 1) { die("usage: <size_in_bytes> <file_name>\n"); }

open(FILE,">" . $ARGV[0]) or die "Can't open file for writing\n";

# you can control the range of characters here
my $minimum = 32;
my $range = 96;

for ($i=0; $i< $ARGV[1]; $i++) {
    print FILE chr(int(rand($range)) + $minimum);
}

close(FILE);

Его цель - сгенерировать файл указанного размера, заполненный случайными символами .

Он работает, но довольно медленно. Для записи случайного файла размером 10 МБ требуется несколько секунд.
Есть ли у кого-нибудь предложения / советы о том, как сделать это быстрее / лучше? Также не стесняйтесь указывать на распространенные ошибки новичков.

6
задан Community 23 May 2017 в 12:06
поделиться

3 ответа

  1. You could ask rand to create more than one value for you each time you call it.
  2. Collect several characters together before calling print. Printing one character at a time is inefficient.

for (my $bytes = 0; $bytes < $num_bytes; $bytes += 4) {
    my $rand = int(rand($range ** 4));
    my $string = '';
    for (1..4) {
        $string .= chr($rand % $range + $minimum);
        $rand = int($rand / $range);
    }
    print FILE $string;
}
6
ответ дан 9 December 2019 в 20:38
поделиться

Записать данные потока из / dev / random.

#!/usr/bin/perl
use File::Copy;
if ($#ARGV < 1) { die("usage: <size_in_bytes>\n"); }
copy("/dev/random","tmp", $ARGV[0]) or die "Copy failed: $!";

код не тестировался.

Изменить: Поскольку вам нужен диапазон, сделайте это.

Ваш диапазон от 96 до 32, что представляет собой пробел 64. 64 = 01000000b (0x40 в шестнадцатеричном формате). Просто сгенерируйте свои числа и выполните побитовое И против числа, которое представляет собой диапазон значений, которые должны быть сгенерированы-1, и добавьте нижнюю границу, предварительно сформировав побитовое ИЛИ с его значением (00100000b или 0x20)

Это позволит вам сделать такие вещи, как взять любую случайную строку (просто прочитать необработанный шестнадцатеричный код из / dev / random) и преобразовать данные в ваш диапазон.

5
ответ дан 9 December 2019 в 20:38
поделиться

Если вам нужны случайные числа из диапазона, я не знаю более эффективного способа. Ваш сценарий адаптирован к моим предпочтениям:

#!/usr/bin/perl

use warnings;
use strict;

die("usage: $0 <size_in_bytes> <file_name>\n") unless @ARGV == 2;

my ($num_bytes, $fname) = @ARGV;

open(FILE, ">", $fname) or die "Can't open $fname for writing ($!)";

my $minimum = 32;
my $range = 96;

for (1 .. $num_bytes) {
    print FILE pack( "c", int(rand($range)) + $minimum);
}

close(FILE);

Я использую pack ("c") , когда мне действительно нужен двоичный файл. chr () тоже может подойти, но IIRC на самом деле это зависит от того, какую кодировку символов использует ваша среда (подумайте, ASCII или utf8.)

Кстати, если вам действительно нужен двоичный файл для совместимости с Windows, вы можете хотите добавить binmode FILE; после open .

В противном случае, если диапазон не является обязательным, вы можете просто dd if = / dev / random of = $ filename bs = 1 count = $ size_of_the_output (или в Linux более быстрый крипто-небезопасный / dev / urandom ). Но это будет намного медленнее, поскольку / dev / random действительно пытается доставить реальные случайные биты - по мере их появления. И если их недостаточно (например, ваша платформа не имеет H / W RNG), тогда производительность действительно пострадает - по сравнению с невероятно быстрым генератором псевдослучайных чисел libc (Perl использует внутренне для реализации rand () ).

1
ответ дан 9 December 2019 в 20:38
поделиться
Другие вопросы по тегам:

Похожие вопросы: