Writing a 1GB file in perl
One of my pleasures in perl is learning the C language again. Something about the perl language makes it easier to write C, but while sharing the same space in my brain.
So how can I write a trivial program to write exactly one GB (2^30) of data to disk?
first in perl- (Of course you prototype in perl!)
But since my c program is cleaner, here’s the C program
# include <stdio.h>
# include <assert.h>
// this simple program writes 1 GB of data, to a file called "somefile"
// setup 256 bytes of data
char data2[] =
"0x000x000x000x000x000x000x000x000x000x000x000x000x000x000x000x000x000x000x000x000x000x000x000x000x000x000x000x000x000x000x000x000x000x000x000x000x000x000x000x000x000x000x000x000x000x000x000x000x000x000x000x000x000x000x000x000x000x000x000x000x000x000x000x00";
// using `calc` from debian; do two simple calculations.
// answers are shown on even lines below
/* 2**30/256
4194304
4194304 / 1024
4096
*/
void main () {
FILE* fp= fopen("somefile", "w");
assert (fp);
for (int i=0;i< 4096*1024;i++)
fwrite (data2,256,1,fp); // lol don't use sizeof
}
compile and run
$ cc writeGB.c -g
$ time ./a.out
since I used bash’s time
command, it tells me it worked in 1.991s
$ stat somefile
stat tells me that the file is exactly 1073741824 bytes, which is what I expect.
now the perl version
#! /usr/bin/perl
use strict;
use warnings;
use 5.010;
# can perl write exactly a 2GB file? or whatever? this writes 1GB ... GiB
die unless open my $fhandl, ">somefile";
my $bytes = 2**30; # 1 GiB in bytes
my $data2 = "0y00" x 64; # 256 bytes
for (my $a=0; $a<$bytes ;$a+=256 ) {
print $fhandl $data2;
}
using binmode doesn’t seem to speed it up … I thought it would have. Oddly enough, perl is faster than the compiled C code, by about 5%. I am gobsmacked, but It must be buffering a few system calls.
BTW, less
doesn’t like viewing the file due to the lack of newlines. I had to kill the process.
I can make sure the bytes are written to spinning rust by appending two lines to the perl source code
close $fhandl;
system 'sync', 'somefile'; # alternatively use File::Sync on cpan, (builds with XS) (sync is not flush)
So, project finished. A file that’s exactly 1 GB. (or GiB for the youngsters). everything about this was easy and fun. Maybe I’ll turn it into a swap file.
Probably be faster if you bump up the chunk size to whatever the block size of your underlying fs is. Or a multiple thereof.
Or flush and sync the file before closing: