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.

2 Comments

Probably be faster if you bump up the chunk size to whatever the block size of your underlying fs is. Or a multiple thereof.

close $fhandl;
system 'sync', 'somefile';  # alternatively use  File::Sync on cpan, 

Or flush and sync the file before closing:

$fhandle->flush;
$fhandle->sync;
$fhandle->close;

Leave a comment

About kanliot

user-pic avid reader