2010-08-10 20 views
6

To jest mój pierwszy skrypt Perla. Ever:Czy istnieje skuteczniejszy sposób generowania losowego pliku w Perlu?

#!/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); 

Jego celem jest generate a file in a specified size filled with random characters.

To działa, ale jest dość powolna. Napisanie losowego pliku 10 MB zajmuje kilka sekund.
Czy ktoś ma sugestie/wskazówki, jak zrobić to szybciej/lepiej? Możesz również wskazać typowe błędy dla początkujących.

Odpowiedz

6
  1. Możesz poprosić rand o utworzenie dla ciebie więcej niż jednej wartości za każdym razem, gdy ją wywołasz.
  2. Zbierz kilka znaków, zanim zadzwonisz pod numer print. Drukowanie pojedynczej litery na raz jest nieefektywne.

 

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; 
} 
+1

I * think * Perl działa najlepiej w porcjach 4k wysyłanych do strumienia. Powiązane ze zmianą rozmiaru bufora strumieniowego: http://stackoverflow.com/questions/1251062/how-can-i-set-the-file-read-buffer-size-in-perl-to-optimize-it-for -duże pliki – Incognito

+0

Dlaczego używasz 'my $ rand = int (rand ($ range ** 4))' i 'chr ($ rand% $ range + $ minimum)' zamiast po prostu 'my $ rand = int (rand ($ range) 'i' chr ($ rand + $ minimum) '? – Alexander

+0

' rand ($ range ** 4) 'zawiera wystarczającą ilość informacji do wygenerowania 4 losowych znaków – mob

4

Zapisuj dane strumieniowe z/dev/random. Nie został przetestowany kod

#!/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: $!"; 

.

Edytuj: Skoro chcesz zakresu, zrób to.

Twój zakres wynosi pomiędzy 96 i 32, które znajduje się przestrzeń 64. 64 = 01000000b (0x40 w heksanie). Wystarczy wygenerować swoje numery i preform bitowego i przeciwko numer, który jest zakres wartości mają być generowane-1 i dodać dolnej granicy przez preforming bitowym OR z jego wartość (00100000b lub 0x20)

To pozwoli robisz rzeczy takie jak dowolny ciąg losowy (po prostu odczytaj surowe heksy z/dev/random) i przekształć dane tak, by znalazły się w twoim zasięgu.

+1

znaczy/dev/random, prawdopodobnie. Zwróć uwagę, że są to wyłącznie systemy podobne do uniksowych. –

+0

Tak, dziękuję, że to zauważyłeś. Założę się, że jest na unixie w oparciu o lokalizację perla (usr/bin). – Incognito

+0

To nie pozwala mi kontrolować, które postacie zostaną zapisane, czy nie. – quantumSoup

1

Jeśli potrzebujesz liczb losowych z szeregu, nie jestem świadomy bardziej efektywny sposób. Skrypt dostosowany do moich upodobań:

#!/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); 

używam pack("c") kiedy naprawdę trzeba binarny. chr() może być w porządku, ale IIRC to faktycznie zależy od charakteru środowiska kodowania używa (myślę ASCII vs. utf8).

BTW, jeśli naprawdę potrzebujesz plik binarny dla zgodności z systemem Windows może chcesz dodać binmode FILE; po open .

W przeciwnym razie, jeśli zakres jest opcjonalny, można po prostu dd if=/dev/random of=$filename bs=1 count=$size_of_the_output (lub w systemie Linux - szybszy kod-bezpieczny /dev/urandom). Ale byłoby to znacznie wolniejsze, ponieważ naprawdę próbuje dostarczyć rzeczywiste losowe bity, gdy tylko staną się dostępne. A jeśli ich nie ma (np. Twoja platforma nie ma H/W RNG), to wydajność naprawdę ucierpiałaby - w porównaniu do niesamowicie szybkiego generatora liczb pseudolosowych libc (Perl używa wewnętrznie do implementacji rand()).

Powiązane problemy