0

Hey, I was wondering if anyone knew how I could compress a tarball file with gzip. I checked out this already and compressed a tarball successfully, although I want to then compress that tarball with gzip instead of libbz2.

I have also tried implementing the gztack function from the gzappend.c example from the zlib source code. but ended up getting a bunch of errors and deprecating warnings, so I figured I won't get much out of a deprecated example.

Does anyone know how I can achieve this, preferably with the zlib library?

Community
  • 1
  • 1
daxvena
  • 1,140
  • 3
  • 14
  • 30
  • 2
    By far the easiest way to do this is to pass the `z` option to `tar` when you create the tar file. What's your motivation for wanting to do this in C++? – Greg Hewgill Feb 14 '11 at 02:05
  • 1
    My motivation is that I want this to be cross platform and usually on other platforms they won't have tar installed in the system. – daxvena Feb 14 '11 at 02:07
  • 2
    which linux platforms do not have tar? – Sam Miller Feb 14 '11 at 02:12
  • Not sure, I just put linux as a tag because that is what I am currently working with, I will probably use Windows/Mac in the future. It just doesn't seem right using a system call, even if you are sure MOST of the platforms you are developing it for should have it. – daxvena Feb 14 '11 at 02:15
  • @Sam Back in the bronze age some of the one- and two-floppy systems didn't have gnutar and you had to zip them separately. Aside from that I haven't a clue. – dmckee --- ex-moderator kitten Feb 14 '11 at 02:15

4 Answers4

3

Use the zlib routines gzopen to open a compressed stream, gcwrite to write data to it and compress it, and gzclose to close it. Here's a complete program that compresses one file to another:

#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <zlib.h>

int main(int argc, char **argv)
{
  if(argc < 3)
  {
    fprintf(stderr, "Usage: %s input output\n", argv[0]);
    return 1;
  }

  // Open input & output files
  FILE *input = fopen(argv[1], "rb");
  if(input == NULL)
  {
    fprintf(stderr, "fopen: %s: %s\n", argv[1], strerror(errno));
    return 1;
  }

  gzFile output = gzopen(argv[2], "wb");
  if(output == NULL)
  {
    fprintf(stderr, "gzopen: %s: %s\n", argv[2], strerror(errno));
    fclose(input);
    return 1;
  }

  // Read in data from the input file, and compress & write it to the
  // output file
  char buffer[8192];
  int N;
  while((N = fread(buffer, 1, sizeof(buffer), input)) > 0)
  {
    gzwrite(output, buffer, N);
  }

  fclose(input);
  gzclose(output);

  return 0;
}

Use it like this:

$ ./mygzip input output.gz
$ diff input <(gunzip < output.gz)  # Verify that it worked
Adam Rosenfield
  • 390,455
  • 97
  • 512
  • 589
1

Have you tried simply using zlib? There's a tutorial here: http://www.zlib.net/zlib_how.html

That's a good way to make a gzip file, certainly. By your stated goals I would assume that using popen() or system() to run a program is not so great (requires the machine to have something else installed, not to mention it's less efficient if you're going to do this a lot).

John Zwinck
  • 239,568
  • 38
  • 324
  • 436
0

There's a clear way to do this in the shell:

gzip ball.tar

You can have the C++ program uses the popen system call to run the command.

You can also write a wrapper to zlib that emulates c++ iostream (for example http://www.cs.unc.edu/Research/compgeom/gzstream/)

Foo Bah
  • 25,660
  • 5
  • 55
  • 79
0

Constructing a const char* argument string for the tar command and passing it into the system() function in cstdlib.h is probably the simplest way to do that. Or using popen(), as Foo Bah's answer mentioned. I find it hard to believe that your target platforms include ones without tar or gzip, as even recovery shells like BusyBox have access to tar. Once system()/popen() returns (check the return code for success obviously), create an ifstream to the compressed file and do whatever you like with it.

EDIT: When you tag something Linux people tend to assume that means specifically and only Linux. Of course tar will not work for standard installs of Windows operating systems, so in that case, yes, provide a bundled zlib dll and use zlib as John mentions.