Всем привет!
Вот, понадобилось создавать zip-архивы с помощью библиотеки
ZLib . Решил поделиться результатами своих изысканий, может кому и сгодится. Код приводится без всяких претензий на полноту и оригинальность, так... чтоб было с чего начать. Извиняюсь за "расширенную" индикацию ошибок в лице return false
, если понадобится, дополнить труда не составит.
Пример использования:
#include "stdafx.h"
#include "SimpleZipArchive.h"
int main(int argc, char * argv[])
{
CSimpleZipArchive zip("d:\\_myzip.zip" );
zip.AddFile("d:\\file1.txt" );
zip.AddFile("d:\\file2.doc" );
zip.AddFile("d:\\file3.xls" );
zip.RemoveFile("d:\\file2.doc" );
zip.ZipIt();
return 0;
}
Сам класс:
#if !defined(_SIMPLEZIPARCHIVE_H_INCLUDED_)
#define _SIMPLEZIPARCHIVE_H_INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#pragma comment(lib, ".\\zlib\\zlib.lib" )
#include ".\zlib\zip.h"
#include <sys/stat.h>
#include <time.h>
#include <map>
#include <string>
using namespace std;
#define READ_BUFFER_SIZE 65535
//Спасибо тов. Bell-у за наше счастливое детство :)
struct CaseInsensitiveLess : public binary_function<string, string, bool >
{
bool operator ()(const string &s1, const string &s2) const
{
return stricmp(s1.c_str(), s2.c_str()) < 0;
}
};
typedef map<string, bool , CaseInsensitiveLess> STRCI_MAP;
class CSimpleZipArchive
{
public :
CSimpleZipArchive(const char * _zipName = NULL) { SetZipFileName(_zipName); }
virtual ~CSimpleZipArchive() {}
void SetZipFileName(const char * _zipName)
{
if (_zipName && 0 != *_zipName)
m_ZipFileName = _zipName;
}
const char * GetZipFileName() const { return m_ZipFileName.c_str(); }
bool RemoveFile(const char * _fileName)
{
if (!_fileName || 0 == *_fileName) return false ;
STRCI_MAP::iterator findIter = m_Files.find(string(_fileName));
if (findIter != m_Files.end())
{
m_Files.erase(findIter);
return true ;
}
else
return false ;
}
bool AddFile(const char * _fileName)
{
if (!_fileName || 0 == *_fileName) return false ;
pair<STRCI_MAP::iterator, bool > result =
m_Files.insert(STRCI_MAP::value_type(string(_fileName), true ));
return result.second;
}
bool ZipIt() const
{
bool result = false ;
if ( 0 == m_Files.size()) return result;
STRCI_MAP::const_iterator Iter = m_Files.begin();
zipFile zipfile = zipOpen(m_ZipFileName.c_str(), 0);
if (zipfile != NULL)
{
while (Iter != m_Files.end())
{
result = false ;
const char * srcFullFileName = Iter->first.c_str();
const char * p = strrchr(srcFullFileName, '\\' );
const char * srcFileName = (NULL == p) ? srcFullFileName : p + 1;
char read_buf[READ_BUFFER_SIZE];
FILE* file = fopen(srcFullFileName, "rb" );
if (file != NULL)
{
zip_fileinfo zfileinfo = {0};
struct _stat file_stat = {0};
_fstat(_fileno(file), &file_stat);
struct tm* file_time = localtime(&file_stat.st_mtime);
tm_zip* zip_time = &zfileinfo.tmz_date;
memcpy(zip_time, file_time, sizeof (tm_zip));
int compression = Z_BEST_COMPRESSION;
if ( ZIP_OK == zipOpenNewFileInZip(zipfile, srcFileName,
&zfileinfo, NULL, 0, NULL, 0, NULL, Z_DEFLATED, compression))
{
while (!feof(file))
{
result = false ;
size_t count = fread( read_buf, sizeof (char ), READ_BUFFER_SIZE, file );
if (!ferror(file))
{
if ( ZIP_OK == zipWriteInFileInZip(zipfile, read_buf, count))
{
result = true ;
continue ;
}
else break ;
}else break ;
}
result = result && (Z_OK == zipCloseFileInZip(zipfile));
}
result = result && (0 == fclose(file));
}
(result) ? Iter++ : Iter = m_Files.end();
}
result = result && (Z_OK == zipClose(zipfile, NULL));
}
return result;
}
private :
STRCI_MAP m_Files;
string m_ZipFileName;
};
#endif // !defined(_SIMPLEZIPARCHIVE_H_INCLUDED_) RSDN@Home
От:
Аноним
Дата: 23.03.05 12:54
Оценка:
Кстати, вопрос в тему — как добавить в ZIP-архив пустую папку?
Здравствуйте, Аноним, Вы писали:
А>Кстати, вопрос в тему — как добавить в ZIP-архив пустую папку?
Не, не знаю. Не нужно было, не разбирался.
PS.
Вот ведь время летит... Оригинальному посту уже два года (!!!) стукнуло. А вроде как вчера писал
Раз уж тема всплыла, кидаю код с распаковщиком. Чуток отличается от прежнего, переделывался под нужды одной из прог. Функционал по минимуму — простые архивы кушает, без папок. Но всяко лучше чем ничего, может кому и пригодится.
Packer.h
#pragma once
#include <vector>
#include <string>
typedef std::vector<std::string> STR_VEC;
struct CPacker
{
//заархивировать файлы
BOOL Pack(STR_VEC& _files, const char * _zipName);
//разархивировать
BOOL Unpack(const char * _zipName, const char * _dstFolder);
};
Packer.cpp
#include "StdAfx.h"
#include ".\packer.h"
#include ".\zlib\zip.h"
#include ".\zlib\unzip.h"
#include <sys/stat.h>
#include <time.h>
#pragma comment(lib, ".\\zlib\\zlib.lib" )
#define READ_BUFFER_SIZE 65535
BOOL CPacker::Pack(std::vector<std::string>& _files, const char * _zipName)
{
BOOL result = false ;
if ( 0 == _files.size())
return result;
STR_VEC::const_iterator Iter = _files.begin();
zipFile zipfile = zipOpen(_zipName, 0);
if (zipfile != NULL)
{
while (Iter != _files.end())
{
result = false ;
const char * srcFullFileName = Iter->c_str();
const char * p = strrchr(srcFullFileName, '\\' );
const char * srcFileName = (NULL == p) ? srcFullFileName : p + 1;
char read_buf[READ_BUFFER_SIZE];
FILE* file = fopen(srcFullFileName, "rb" );
if (file != NULL)
{
zip_fileinfo zfileinfo = {0};
struct _stat file_stat = {0};
_fstat(_fileno(file), &file_stat);
struct tm* file_time = localtime(&file_stat.st_mtime);
tm_zip* zip_time = &zfileinfo.tmz_date;
memcpy(zip_time, file_time, sizeof (tm_zip));
int compression = Z_BEST_COMPRESSION;
if ( ZIP_OK == zipOpenNewFileInZip(zipfile, srcFileName,
&zfileinfo, NULL, 0, NULL, 0, NULL, Z_DEFLATED, compression))
{
while (!feof(file))
{
result = false ;
size_t count = fread( read_buf, sizeof (char ), READ_BUFFER_SIZE, file );
if (!ferror(file))
{
if ( ZIP_OK == zipWriteInFileInZip(zipfile, read_buf, count))
{
result = true ;
continue ;
}
else
break ;
}else
break ;
}
result = result && (Z_OK == zipCloseFileInZip(zipfile));
}
result = result && (0 == fclose(file));
}
(result) ? Iter++ : Iter = _files.end();
}
result = result && (Z_OK == zipClose(zipfile, NULL));
}
return result;
}
BOOL CPacker::Unpack(const char * _zipName, const char * _dstFolder)
{
BOOL result = FALSE;
unzFile zipFile = unzOpen(_zipName);
if (NULL != zipFile)
{
if (UNZ_OK == unzGoToFirstFile(zipFile))
{
BOOL bContinue = TRUE;
while (bContinue)
{
result = FALSE;
unz_file_info fi;
char filename[MAX_PATH] = {0};
if (UNZ_OK == unzGetCurrentFileInfo(zipFile, &fi,
filename, sizeof (filename), 0, 0, 0, 0))
{
if (UNZ_OK == unzOpenCurrentFile(zipFile))
{
UINT dataLen = fi.uncompressed_size;
BYTE* fileData = new BYTE[dataLen];
if (!fileData)
break ;
if (dataLen == unzReadCurrentFile(zipFile, fileData, dataLen))
{
char filePathName[MAX_PATH] = {0};
strcat(filePathName, _dstFolder);
strcat(filePathName, "\\" );
strcat(filePathName, filename);
FILE* pFile = fopen(filePathName, "wb" );
if (pFile)
{
result = (dataLen == fwrite(fileData, 1, dataLen, pFile));
result = result && (0 == fclose(pFile));
}
}
delete [] fileData;
}
result = result && (UNZ_OK == unzCloseCurrentFile(zipFile));
}
if (!result)
break ;
if (UNZ_END_OF_LIST_OF_FILE == unzGoToNextFile(zipFile))
bContinue = FALSE;
}
}
result = result && (UNZ_OK == unzClose(zipFile));
}
return result;
}
А кстати, не сталкивался ли кто с такой проблемой — при добавлении файлов в ZIP-архив время, сохраненное в файле, сохраняется для некоторых из файлов (с вероятностью 1/10 прмерно)увеличенным на 1 секунду? Причем проблема проявляется только на дисках с NTFS, с FAT32 все нормально.
Заранее tnx.
От:
Аноним
Дата: 09.11.05 09:30
Оценка:
Здравствуйте, DmitryElj, Вы писали:
DE>А кстати, не сталкивался ли кто с такой проблемой — при добавлении файлов в ZIP-архив время, сохраненное в файле, сохраняется для некоторых из файлов (с вероятностью 1/10 прмерно)увеличенным на 1 секунду? Причем проблема проявляется только на дисках с NTFS, с FAT32 все нормально.
DE>Заранее tnx.
В зипе хранится dostime, секунды в котором кодируются 5 битами, т.е. хранятся только "чётные" секунды. Нечётные округляются вверх.
Здравствуйте, Аноним, Вы писали:
А>В зипе хранится dostime, секунды в котором кодируются 5 битами, т.е. хранятся только "чётные" секунды. Нечётные округляются вверх.
Я уже разобрался, и даже сам себе написал ответ:
http://www.rsdn.ru/Forum/Message.aspx?mid=1478348&only=1Автор: DmitryElj Дата: 09.11.05
В любом случае, спасибо.
Re[3]: CSimpleZipArchive + folders support
Оказалось что предложенный код не умеет работать с папками в архиве. Мой посильный вклад:
if (UNZ_OK == unzGetCurrentFileInfo(zip_file, &fi,
filename, sizeof(filename), 0, 0, 0, 0))
{
if(fi.uncompressed_size)//file
{
if (UNZ_OK == unzOpenCurrentFile(zip_file))
{
UINT data_len = fi.uncompressed_size;
BYTE* file_data = new BYTE[data_len];
if (!file_data)
break;
if(data_len == unzReadCurrentFile(zip_file, file_data, data_len))
{
char file_path_name[MAX_PATH] = {0};
strcat(file_path_name, i_dest_dir.c_str());
strcat(file_path_name, "\\");
strcat(file_path_name, filename);
FILE* pFile = fopen(file_path_name, "wb");
if (pFile)
{
result = (data_len == fwrite(file_data, 1, data_len, pFile));
result = result && (0 == fclose(pFile));
}
}
delete [] file_data;
}
result = result && (UNZ_OK == unzCloseCurrentFile(zip_file));
}
else//dir
{
std::string new_dir = i_dest_dir;
new_dir += "\\";
new_dir += filename;
_mkdir(new_dir.c_str());
result = true;
}
}
Здравствуйте, Gosha, Вы писали:
G>Здравствуйте, Аноним, Вы писали:
А>>Кстати, вопрос в тему — как добавить в ZIP-архив пустую папку?
G>Не, не знаю. Не нужно было, не разбирался.
G>PS.
G>Вот ведь время летит... Оригинальному посту уже два года (!!!) стукнуло. А вроде как вчера писал
G>Раз уж тема всплыла, кидаю код с распаковщиком. Чуток отличается от прежнего, переделывался под нужды одной из прог. Функционал по минимуму — простые архивы кушает, без папок. Но всяко лучше чем ничего, может кому и пригодится.
G>Packer.h
G>G>#pragma once
G>#include <vector>
G>#include <string>
G>typedef std::vector<std::string> STR_VEC;
G>struct CPacker
G>{
G> //заархивировать файлы
G> BOOL Pack(STR_VEC& _files, const char * _zipName);
G> //разархивировать
G> BOOL Unpack(const char * _zipName, const char * _dstFolder);
G>};
G>
G>Packer.cpp
G>G>#include "StdAfx.h"
G>#include ".\packer.h"
G>#include ".\zlib\zip.h"
G>#include ".\zlib\unzip.h"
G>#include <sys/stat.h>
G>#include <time.h>
G>#pragma comment(lib, ".\\zlib\\zlib.lib" )
G>#define READ_BUFFER_SIZE 65535
G>BOOL CPacker::Pack(std::vector<std::string>& _files, const char * _zipName)
G>{
G> BOOL result = false ;
G> if ( 0 == _files.size())
G> return result;
G> STR_VEC::const_iterator Iter = _files.begin();
G> zipFile zipfile = zipOpen(_zipName, 0);
G> if (zipfile != NULL)
G> {
G> while (Iter != _files.end())
G> {
G> result = false ;
G> const char * srcFullFileName = Iter->c_str();
G> const char * p = strrchr(srcFullFileName, '\\' );
G> const char * srcFileName = (NULL == p) ? srcFullFileName : p + 1;
G> char read_buf[READ_BUFFER_SIZE];
G> FILE* file = fopen(srcFullFileName, "rb" );
G> if (file != NULL)
G> {
G> zip_fileinfo zfileinfo = {0};
G> struct _stat file_stat = {0};
G> _fstat(_fileno(file), &file_stat);
G> struct tm* file_time = localtime(&file_stat.st_mtime);
G> tm_zip* zip_time = &zfileinfo.tmz_date;
G> memcpy(zip_time, file_time, sizeof (tm_zip));
G> int compression = Z_BEST_COMPRESSION;
G> if ( ZIP_OK == zipOpenNewFileInZip(zipfile, srcFileName,
G> &zfileinfo, NULL, 0, NULL, 0, NULL, Z_DEFLATED, compression))
G> {
G> while (!feof(file))
G> {
G> result = false ;
G> size_t count = fread( read_buf, sizeof (char ), READ_BUFFER_SIZE, file );
G> if (!ferror(file))
G> {
G> if ( ZIP_OK == zipWriteInFileInZip(zipfile, read_buf, count))
G> {
G> result = true ;
G> continue ;
G> }
G> else
G> break ;
G> }else
G> break ;
G> }
G> result = result && (Z_OK == zipCloseFileInZip(zipfile));
G> }
G> result = result && (0 == fclose(file));
G> }
G> (result) ? Iter++ : Iter = _files.end();
G> }
G> result = result && (Z_OK == zipClose(zipfile, NULL));
G> }
G> return result;
G>}
G>BOOL CPacker::Unpack(const char * _zipName, const char * _dstFolder)
G>{
G> BOOL result = FALSE;
G> unzFile zipFile = unzOpen(_zipName);
G> if (NULL != zipFile)
G> {
G> if (UNZ_OK == unzGoToFirstFile(zipFile))
G> {
G> BOOL bContinue = TRUE;
G> while (bContinue)
G> {
G> result = FALSE;
G> unz_file_info fi;
G> char filename[MAX_PATH] = {0};
G> if (UNZ_OK == unzGetCurrentFileInfo(zipFile, &fi,
G> filename, sizeof (filename), 0, 0, 0, 0))
G> {
G> if (UNZ_OK == unzOpenCurrentFile(zipFile))
G> {
G> UINT dataLen = fi.uncompressed_size;
G> BYTE* fileData = new BYTE[dataLen];
G> if (!fileData)
G> break ;
G> if (dataLen == unzReadCurrentFile(zipFile, fileData, dataLen))
G> {
G> char filePathName[MAX_PATH] = {0};
G> strcat(filePathName, _dstFolder);
G> strcat(filePathName, "\\" );
G> strcat(filePathName, filename);
G> FILE* pFile = fopen(filePathName, "wb" );
G> if (pFile)
G> {
G> result = (dataLen == fwrite(fileData, 1, dataLen, pFile));
G> result = result && (0 == fclose(pFile));
G> }
G> }
G> delete [] fileData;
G> }
G> result = result && (UNZ_OK == unzCloseCurrentFile(zipFile));
G> }
G> if (!result)
G> break ;
G> if (UNZ_END_OF_LIST_OF_FILE == unzGoToNextFile(zipFile))
G> bContinue = FALSE;
G> }
G> }
G> result = result && (UNZ_OK == unzClose(zipFile));
G> }
G> return result;
G>}
G>
Пока на собственное сообщение не было ответов, его можно удалить.
Удалить