Jump to content
  • Advertisement
Sign in to follow this  
relpats_eht

Compress File with zlib

This topic is 5408 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I have been unable to exactly decipher what the zlib functions are do, as they simply dont seem straight forward to me,id be fine if i could find a code example somewhere, but a c tutoiral of zlib is extremly hard to come across apparently. If somone would please just show me how to read an uncompressed file, compress it, and store it in another file, i would be greatly appreciative. thank you.

Share this post


Link to post
Share on other sites
Advertisement
Take a look at compress.c in the root of the ZLIB source. That demonstrates the simple case of compressing data in a buffer into another buffer.

You shouldn't need much more unless you want to start using the streaming features - but I'd still reccommed starting with compressing a whole buffer in memory.

Share this post


Link to post
Share on other sites
the zlib manual states something about mmaping a file so that it can be compressed at once. what exactly does that mean?


**edit**

i wrote this function up real quick, but it doesnt work. it creates the file, and inserts data, put, the data isn't uncompressed correctly when opened with winzip (which can uncompress gziped files), so im wondering whatim doing wrong...

int zcmpr(const char* filename){
char fname2[strlen(filename) + 4];
FILE * ufile;
gzFile cfile;
char buffer[256];
char c;
int i = 0;
ufile = fopen(filename, "r");

if (ufile == NULL) {
perror("Error opening file");
return 0;
}

while (!feof(ufile)) {
c = fgetc(ufile);
buffer = c;
}
fclose(ufile);
strcpy(fname2, filename);
strcat(fname2, ".gz");

cfile = gzopen(fname2, "wb");
gzputs(cfile, buffer);
gzclose(cfile);

return 1;
}


[Edited by - relpats_eht on September 26, 2004 5:11:37 PM]

Share this post


Link to post
Share on other sites
Zlib Manual

  1. Open a gzFile with gzopen.
  2. If that succeeded, create a file stream (not gz) to write to.
  3. Choose a heuristic size of your write chunk.
  4. Create an unsigned int buffer with the write chunk. You can use calloc to create the buffer and unsigned int for the type.
  5. Use gzread by passing in the gzFile of the compressed file, the pointer to the buffer, and the chunk size you wish to read.
  6. Check the return value of the gzread and if it is not the same as your read size, see if it is -1 or 0. If it is -1, then the read failed; clean up. If it is 0 then you reached EOF or the file size is 0. Otherwise it is at EOF and you could only read the returned size.
  7. Write the returned size to the output file.
  8. Repeat 5 through 7 until 6 returns 0.

Share this post


Link to post
Share on other sites
I don't know about zlib so much, but mmapping means that the file is mapped into memory. So after you have mmapped a file to a memory, you will have a pointer to a memory region where your file starts and you can begin reading/writing, like you would when using "normal" pointers. On linux (possibly on all POSIX compliant systems) the instruction (one of them) is called (supprise supprise) mmap. Try typing "info mmap". You'll get Memory Mapped I/O section of libc.info.

Share this post


Link to post
Share on other sites
Here's a quick example, may not work but you should get the general idea of how to do things.


bool CompressFile(const std::string &InFile, const std::string &OutFile)
{

//these are the compressed and uncompressed sizes of the file
uLongf g_CompSize;
uLongf g_OrigSize;

//buffers to store compressed and orginal data
void *g_CompDataBuff = NULL;
void *g_OrigDataBuff = NULL;

//open the files
FILE *g_InFilePtr = fopen(InFile.c_str());
FILE *g_OutFilePtr = fopen(OutFile.c_str());

//get filesize of original file, there's probably a better way
//to do this.
fseek(g_InFilePtr, 0, SEEK_END);
g_OrigSize = ftell(g_InFilePtr);
rewing(g_InFilePtr);

//allocate the buffer then read the data in
g_OrigDataBuff = malloc(g_OrigSize);
fread(g_OrigDataBuff, g_OrigSize, 1, g_InFilePtr);

//compress the data
g_CompDataBuff = malloc((g_OrigSize + (g_OrigSize * 0.1) + 12));
compress2((Bytef*)g_CompDataBuff, &g_CompSize, (const Bytef*)g_OrigDataBuff, Z_BEST_COMPRESSION);

//write the compressed data to the output file
fwrite(g_CompDataBuff, g_CompDataSize, 1, g_OutFilePtr);

//cleanup
free(g_OrigDataBuff);
free(g_CompDataBuff);

fclose(g_InFilePtr);
fclose(g_OutFilePtr);

return true;
}





There's probably a few errors in there but as I've just hacked together that function by ripping pieces from different source I've got on my HD but it does work, you'll wanna add in error checking which I have missed out to make it more readable.

It's a bit of a memory hog as it reads and compresses the file in one go, there is alternate ways to this by using the stream based compression methods, these are a bit more complicated to use but do have the advantage of being able to read in and compress a file in arbitrary sized chunks.

Share this post


Link to post
Share on other sites
thanx for all the help. i ended up modifying my code to make something taht works, even if it could be improved memory wise, it still works, so im happy.

int zcmpr(const char* filename){
char fname2[strlen(filename) + 4];
FILE * ufile;
gzFile cfile;
char buffer[256];
long fsize;
char c;
int i = 0;

strcpy(fname2, filename);
strcat(fname2, ".gz");
ufile = fopen(filename, "rb");
cfile = gzopen(fname2, "wb");

if (ufile == NULL || cfile == NULL) {
perror("Error opening file");
return 0;
}

fseek(ufile, 0, SEEK_END);
fsize = ftell(ufile);
rewind (ufile);

for (fsize=fsize; fsize >= 0; fsize-=256) {
if (fsize >= 256) {
fread (buffer, 1, 256, ufile);
gzwrite(cfile, buffer, 256);
} else {
fread (buffer, 1, fsize, ufile);
gzwrite(cfile, buffer, fsize);
}
}

fclose(ufile);
gzclose(cfile);

return 1;
}



if anyone has any suggestions as to improving it, however, i would still be appreciative... now on to uncompression. shall certainly be much easier now that i know what im doing.

Share this post


Link to post
Share on other sites
fread will return the amount of data read. When you get to the end of the file, you might not have read a block of 256. You might want to gzwrite only the amount you read.

Share this post


Link to post
Share on other sites
i do. i find out the length of the file, then, in the for loop, write to the gz file 256 chars at a time, checkign if their are 256 chars left by subtrsacting from the filesize every time, if their arent 256 chars left, it just writes whatevers left by using whatever number remains in fsize...

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!