Is there a more efficient way to generate a random file in Perl?

This is my first Perl script. Ever:

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

Its purpose is to generate a file in the specified size, filled with random characters .

It works, but it is rather slow. It takes a few seconds to write a 10 MB random file.
Does anyone have any suggestions / tips on how to make this faster / better? Also do not hesitate to indicate the general mistakes of beginners.

+6
random file-io perl
source share
3 answers
  • You can ask rand to create several values ​​for you each time you call it.
  • Collect some characters 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
source share

Writing stream data from / 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: $!"; 

not verified.

Edit: Since you want a range, do it.

Your range is from 96 to 32, which is 64. 64 = 01000000b (0x40 in hexadecimal format). Just generate your numbers and prepare a bitwise AND versus a number, which is the range of values ​​that should be generated-1, and add a lower border, having previously formed a bitwise OR with its value (00100000b or 0x20)

This will allow you to do something like any random line (just read raw hex from / dev / random) and convert the data to your range.

+4
source share

If you need random numbers from a range, I don't know a more efficient way. Your script is tuned to my preferences:

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

I use pack("c") when I really need a binary. chr() can also be great, but IIRC really depends on what character is used to encode your environment (I think ASCII vs. utf8.)

By the way, if you really need a binary file for compatibility with Windows, you can add binmode FILE; after open .

Otherwise, if the range is optional, you can simply dd if=/dev/random of=$filename bs=1 count=$size_of_the_output (or faster on crypto-unsafe /dev/urandom on Linux). But this will be much slower since /dev/random really trying to deliver real random bits - as they appear. And if they are not enough (for example, your platform does not have H / W RNG), then the performance will really suffer - compared to the incredibly fast pseudo random number generator libc (Perl uses internally to implement rand() ).

+1
source share

All Articles