Manoj Rao bio photo

Manoj Rao

Your Average Common Man

Email Twitter Github

In an earlier post, I concluded that using a pure C++ approach to untarring the archive file may be viable. But given that there are only so many ways std::fstream can be used to read/write chunked files we effectively do a mean reversion in our implementation to the original K&R approach intentionally or otherwise.

To discuss I would like to go back to the SO Question

FWIW, I agree with the top answer that “KISS-C++-Streambuffer-Way” is the most readable and intuitive code so you should use it when possible.

However, in the case of a tar/untar code, effectively we are splitting the file into its constituents by going throug the header info to create the dir hierarchy with appropriate file permission. Further to the end we perform a checksum validation.

This requires us to know the sizes of individual files which implies that we make a local copy into a buffer either chunked or whole size of the file itself. But copying an entire file results in memory bloat for large archives. Therefore, I argue that K&R win again!

Note: In the interest of brevity, I have left out the cleanup code here

ANSI-C-WAY

    char buf[BUFSIZ];
    size_t size;

    FILE* source = fopen("from.ogv", "rb");
    FILE* dest = fopen("to.ogv", "wb");

    // clean and more secure
    // feof(FILE* stream) returns non-zero if the end of file indicator for stream is set

    while (size = fread(buf, 1, BUFSIZ, source)) {
        fwrite(buf, 1, size, dest);
    }

POSIX-WAY (K&R use this in “The C programming language”, more low-level)

    char buf[BUFSIZ];
    size_t size;

    int source = open("from.ogv", O_RDONLY, 0);
    int dest = open("to.ogv", O_WRONLY | O_CREAT /*| O_TRUNC/**/, 0644);

    while ((size = read(source, buf, BUFSIZ)) > 0) {
        write(dest, buf, size);
    }

KISS-C++-Streambuffer-WAY

    ifstream source("from.ogv", ios::binary);
    ofstream dest("to.ogv", ios::binary);

    dest << source.rdbuf();

COPY-ALGORITHM-C++-WAY

    ifstream source("from.ogv", ios::binary);
    ofstream dest("to.ogv", ios::binary);

    istreambuf_iterator<char> begin_source(source);
    istreambuf_iterator<char> end_source;
    ostreambuf_iterator<char> begin_dest(dest); 
    copy(begin_source, end_source, begin_dest);

OWN-BUFFER-C++-WAY

    ifstream source("from.ogv", ios::binary);
    ofstream dest("to.ogv", ios::binary);

    // file size
    source.seekg(0, ios::end);
    ifstream::pos_type size = source.tellg();
    source.seekg(0);
    // allocate memory for buffer
    char* buffer = new char[size];

    // copy file    
    source.read(buffer, size);
    dest.write(buffer, size);

    // clean up
    delete[] buffer;

My Podcast!

If you like topics such as this then please consider subscribing to my podcast. I talk to some of the stalwarts in tech and ask them what their favorite productivity hacks are:

Available on iTunes Podcast

Visit Void Star Podcast’s page on iTunes Podcast Portal. Please Click ‘Subscribe’, leave a comment.

Get it iTunes