Есть некий набор данных который создаёт программа. Надо их опяттаки программно сжать в ZIP и сохранить. Разумеется хочется чтоб была возможность следить за процеесом для возможности информировать сколько осталось время до конца сжатия. Всякие вызовы сторонних EXE отметаються сразу. Ну и кросплатформенность ни кто не отменял.
Может кто в курсе как это организовать ?
помоему на прогорге это обширно обсуждалось. Можно http://doc.crossplatform.ru/qt/4.5.0/qbytearray.html#qCompress
Вот чего накопал по этой теме:
zlib (та что с Qt) - только методы сжатия данных.
http://quazip.sourceforge.net/ - не поддерживает подкаталоги
http://www.info-zip.org/ - нет информации (надо разбиратся)
http://zziplib.sourceforge.net/ - нет информации (надо разбиратся)
Могут оказатся полезными:
http://qtnode.net/wiki?title=Self-Extracting_Installer
http://osdab.42cows.org/?mode=advanced - какие-то фрагменты кода на C++/Qt, в том числе http://osdab.42cows.org/snippets/zip.php?mode=advanced
у тролей есть zlib как 3rdparty
src/3rdparty/zlib/
http://qt.nokia.com/doc/4.5/3rdparty.html#data-compression-library-version-1-2-3
Если как сжать набор байт стало относительно понятно.
Но вот как сделать прогесбар пока не ясно. Вызвать тот же qCompress и тупо ждать неизвестно сколько пока он сжимает как то совсем мимо цели Т.к. процесс сжатия может занять достаточно длительное время то прогрессбар просто обязан быть.
Да и что делать для сжать папки с вложенными папками и файлами тоже не ясно.
Городить огород с собственным форматом выходного файла нельзя т.к. необходимо чтобы результат сжатия можно было распаковатть классическим ZIP-ом.
flankerr,
что ни одно из предоложенных решений Юрием не предоставляет возможности сжимать вложенные паки?
и никак не прикрутишь прогрессБар?
kwisp,
QuaZIP
Zlib
qCompress
жмут поток т.е. папку с вложением подсунуть нельзя. И как правильно сказал Litkevich Yuriy, нет обратной связи.
flankerr, видимо у тебя один выход - заниматся раскопками ОпенСорсных проектов типа http://7-zip.org.ua/ru/help/supported_formats.html#zip...
Однако исодники у них открыты, или я ошибаюсь?
Можно посмотреть решение в KDE. Там правда все сделано глобально, т.е. есть целая иерархия классов начиная с KArchive. У него есть наследник KZip.
Или посмотреть на библиотеку libzip. Она сишная, но можно самому написать враппер для C++ со всем необходимым функционалом.
Также вроде есть готовый враппер libzipios++.
в KDE в большенстве случаев индикатор выполнения болтается туда-сюда.
А почему автору нельзя использовать сторонние архиваторы?
Проще, ИМХО, через QProcess их вызывать и в опциях командной строки подсовывать нужные каталоги для сжатия...
Для этого в самой программе автора определять - какие из архиваторов находятся в системе... НЕ ?
kuzulis,
первый пост об этом говорит.
flankerr
Архивирование с вложенными каталогами и отображением прогресса можно сделать, используя Info-ZIP. Архив получается вполне стандартный и распакуется везде. Надо только собрать zip и unzip как dll и написать callback-функцию для отображения прогресса.
//---------------------------------------------------------------------------
// Служебные функции для SimpleUnzip
//---------------------------------------------------------------------------
int WINAPI DummyPrint(LPSTR, unsigned long) {return 0;}
int WINAPI DummyReplace(LPSTR) {return 0;}
int WINAPI DummyPassword(LPSTR, int, LPCSTR, LPCSTR) {return 0;}
void WINAPI DummyMessage(unsigned long, unsigned long, unsigned,
unsigned, unsigned, unsigned, unsigned, unsigned,
char, LPSTR, LPSTR, unsigned long, char) {}
//---------------------------------------------------------------------------
// Распаковывает zip-архив a_zip в каталог a_dir, заменяя существующие файлы
//---------------------------------------------------------------------------
typedef int (WINAPI * FSINGLEENTRYUNZIP)( int, char **, int, char **,
LPDCL, LPUSERFUNCTIONS );
bool SimpleUnzip( const QString& a_zip, const QString& a_dir )
{
const QString noZip = ru( "Обработка архивов zip невозможна." );
const QString errCap = ru("Ошибка");
const TCHAR* UNZ_DLL_NAME = TEXT("unzip32.dll");
TCHAR szFullPath[_MAX_PATH];
TCHAR* ptr;
if ( SearchPathW( 0, UNZ_DLL_NAME, 0,
sizeof(szFullPath) / sizeof(szFullPath[ 0 ]),
szFullPath, &ptr ) == 0 )
{
mbE( errCap, ru("Не найдена библиотека unzip32.dll.\n" + noZip ) );
return false;
}
HMODULE hUnzipDll = LoadLibraryW( UNZ_DLL_NAME );
if ( hUnzipDll == 0 )
{
mbE( errCap, ru("Не удалось загрузить библиотеку unzip32.dll.\n" + noZip ) );
return false;
}
FSINGLEENTRYUNZIP pWiz_SingleEntryUnzip = (FSINGLEENTRYUNZIP)GetProcAddress(
hUnzipDll, "Wiz_SingleEntryUnzip" );
if ( pWiz_SingleEntryUnzip == 0 )
{
FreeLibrary( hUnzipDll );
mbE( errCap, ru("Неправильная библиотека unzip32.dll.\n" + noZip ) );
return false;
}
LPDCL lpDCL = new DCL;
LPUSERFUNCTIONS lpUserFunctions = new USERFUNCTIONS;
lpUserFunctions->password = DummyPassword;
lpUserFunctions->print = DummyPrint;
lpUserFunctions->replace = DummyReplace;
lpUserFunctions->SendApplicationMessage = DummyMessage;
lpUserFunctions->sound = 0;
lpUserFunctions->ServCallBk = 0;
//set up the flags to be passed into the dll.
lpDCL->ExtractOnlyNewer = 0; // Do not extract only newer
lpDCL->SpaceToUnderscore = 0;
lpDCL->PromptToOverwrite = 0; // "Overwrite all" selected, no query mode
lpDCL->fQuiet = 2; // 0 = all messages, 1 = fewer messages, 2 = no messages
lpDCL->ncflag = 0; // Write to stdout if true
lpDCL->ntflag = 0; // Do not test zip file
lpDCL->nvflag = 0; // Do not give a verbose listing
lpDCL->nfflag = 0; // Do not freshen existing files only
lpDCL->nzflag = 0; // display a zip file comment if true
lpDCL->ndflag = 1; // Recreate directories != 0, skip "../" if < 2
lpDCL->noflag = 1; // Over-write all files
lpDCL->naflag = 0; // Do not convert CR to CRLF
lpDCL->nZIflag = 0;// Do not get ZipInfo
lpDCL->C_flag = 1; // Do not be case insensitive
lpDCL->fPrivilege = 0; // 1 => restore ACLs in user mode,
// 2 => try to use privileges for restoring ACLs
QCString zip = a_zip.local8Bit();
QCString dir = a_dir.local8Bit();
lpDCL->lpszZipFN = const_cast<CHAR*>(static_cast<const char*>(zip));
if ( a_dir.isEmpty() )
lpDCL->lpszExtractDir = 0;
else
lpDCL->lpszExtractDir = const_cast<CHAR*>(static_cast<const char*>(dir));
// qDebug( "zip=%s, dir=%s", lpDCL->lpszZipFN, lpDCL->lpszExtractDir );
int res = pWiz_SingleEntryUnzip( 0, 0, 0, 0, lpDCL, lpUserFunctions );
// qDebug( "unzip retcode=%d", res );
bool rc = res == 0;
delete lpDCL;
delete lpUserFunctions;
FreeLibrary( hUnzipDll );
return rc;
}
Плохо это решение тем, что оно не переносимо, ибо этот Wizard dll API зависим в то время как внутренние вызовы самой библиотеки InfoZip переносимы. Т.е., чтобы понять как это работает и правильно написать код, надо сначала переписать Wizard dll на обычном C++ с использованием STL или обычном Си. Потом уже этот код использовать в Qt.
Форум Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)