[编辑] 通过在调试器中逐步检查库源代码,我发现了一些可以帮助我解决这个问题的方法。zip_open() 函数实际上并没有创建文件,它只是保存......
[编辑] 通过在我的调试器中逐步检查库源,我发现了一些可以帮助我解决这个问题的方法。
zip_open()
函数实际上并不创建文件,它只是保存名称以供稍后使用 zip_close()
。如果当前目录在处理过程中发生更改,并且 在调用之前 未 zip_close()
,则将直接在上次设置为当前的位置创建 ZIP 文件。恕我直言,这是库中的一个错误——如果调用中没有给出路径 zip_open()
,则应将当前目录添加到已保存的 ZIP 文件名前面,以供稍后(正确)使用 zip_close()
.
zip_source_file()
,它需要知道完全限定路径。但如果 zip_file_add()
主要 C:\
开头没有 (或其他), 似乎效果会更好 。
[OP] 我正在尝试学习如何在 Windows 11 上使用 Visual Studio 2022 和 C 使用 libzip 创建 ZIP 文件。完成后,我的文件应该在多个不同的文件夹中包含多个文件。这是我的最终目标。现在,我只想创建一个 ZIP 文件,但该库并没有帮助我正确使用它,因为它没有返回错误,即使它无法执行我要求它执行的任何操作(可检测到)。我不是在寻求帮助来修复我的代码(尽管我当然不会拒绝![微笑]),我真正想在这里学习的是如何使用一个即使明显失败也会返回成功的库来调试问题。
如果我仅使用这个基本序列(已 _UseFqn_
定义)和完全限定的路径/文件名( fqn
),那么实际上就会创建一个 ZIP(Windows 不会读取它,但 7-Zip 可以,所以目前没问题):
zip_open()
zip_source_file(fqn)
zip_file_add(fqn)
zip_close()
如果我习惯 SetCurrentDirectory()
更改为实际包含每个文件的文件夹( fpath
),并尝试添加没有路径信息的文件( fname
),那么我 不会收到任何错误 ,但也不会得到 任何 zip 文件 :
zip_open()
SetCurrentDirectory(fpath)
zip_source_file(fname)
zip_file_add(fname)
zip_close()
如果我尝试使用 添加目录 zip_dir_add()
,上述任一序列都不会出现错误,也不会生成 zip 文件。抱歉这篇文章太长了,但我也要添加我的测试源代码。请对此做一个假设:调用 _MakeZipFile() 的程序是这样调用的: _MakeZipFile("testfile.zip","C:\path\to\file\something.log\0");
//-------------------------------------------------------------------------
// Add a single file to the zip
static int _AddFileToZip( zip_t *zipFile, char *szFileName )
{
int rc = NO_ERROR;
zip_source_t *source;
source = zip_source_file( zipFile, szFileName, 0, ZIP_LENGTH_TO_END );
if( source == NULL )
{
printf( "ZipTest> Failed to src file for zip: '%s'...\n", szFileName );
printf( "ZipTest> libzip: %s\n", zip_strerror( zipFile ) );
rc = ERROR_INVALID_PARAMETER;
}
else if( zip_file_add( zipFile, szFileName, source, ZIP_FL_ENC_RAW ) < 0 )
{
zip_source_free( source );
printf( "ZipTest> Failed to add file to zip: '%s'...\n", szFileName );
printf( "ZipTest> libzip: %s\n", zip_strerror( zipFile ) );
rc = ERROR_INVALID_FUNCTION;
}
else
{ // print a diagnostic for debugging
printf( "ZipTest> added file: '%s'...\n", szFileName );
}
return rc;
}
//-------------------------------------------------------------------------
// Add all folder levels, from top to bottom, recursively
static BOOL _AddFolderToZip( zip_t *zipFile, char *szFolder )
{
char sz[_MAX_PATH];
char *cp;
BOOL bResult;
zip_error_t *pze;
if( ':' == szFolder[1] )
{ // Remove drive letter, if present
szFolder += 2;
}
if( '\\' == *szFolder )
{ // Remove leading backslash, if present
szFolder++;
}
strcpy( sz, szFolder ); // copy so we don't trash the original
cp = strrchr( sz, '\\' );
if( cp && ('\0' == *(cp+1)) )
{ // Remove trailing backslash
*cp = '\0';
}
// Is this a sub-folder?
cp = strrchr( sz, '\\' );
if( cp && (cp != sz) )
{ // Yes, call self to add parent first
*cp = '\0';
if( !_AddFolderToZip( zipFile, sz ) )
{ // Failure, back out with errors
return FALSE;
}
*cp = '\\';
}
// else No, time to add this folder.
bResult = TRUE;
if( zip_dir_add( zipFile, sz, ZIP_FL_ENC_RAW ) < 0 )
{ // Error, but there's one error that is OK...
pze = zip_get_error( zipFile );
if( ZIP_ER_EXISTS != pze->zip_err )
{ // Multiple files in same folder are OK.
bResult = FALSE;
printf( "ZipTest> Failed to add directory to zip: '%s'...\n", szFolder );
printf( "ZipTest> libzip: %s\n", zip_strerror( zipFile ) );
}
}
if( bResult )
{ // print a diagnostic for debugging
printf( "ZipTest> added directory: '%s'...\n", sz );
}
return bResult;
}
// ------------------------------------------------------------------------
#define _UseFqn_ 1 // Use Fully qualified file names and no directories
// comment this out to change directory, add the file folder, and add the filename
// ------------------------------------------------------------------------
// szzSourceList is a buffoer containing some number of NULL terminated
// strings that ends with an empty string (i.e. double-NULL)
BOOL _MakeZipFile( char *szZipFileName, char *szzSourceList )
{
BOOL result = FALSE;
int errorp = NO_ERROR;
zip_t *zipFile;
char *cpFilePath;
zip_error_t ziperror;
zip_error_t *pze;
#if !defined(_UseFqn_)
char szDrive[_MAX_PATH];
char szPath[_MAX_PATH];
char szFile[_MAX_PATH];
char szExt[_MAX_PATH];
char szFolder[_MAX_PATH];
#endif
char szStartPath[_MAX_PATH];
GetCurrentDirectory( sizeof(szStartPath), szStartPath );
zipFile = zip_open( szZipFileName, ZIP_CREATE | ZIP_TRUNCATE, &errorp );
if( zipFile == NULL )
{
zip_error_init_with_code( &ziperror, errorp );
printf( "ZipTest> Failed to open output file '%s'...\n", szZipFileName );
printf( "ZipTest> libzip: %s\n", zip_error_strerror( &ziperror ) );
return FALSE;
}
__try
{
cpFilePath = szzSourceList;
while( *cpFilePath )
{
#if defined(_UseFqn_)
_AddFileToZip( zipFile, cpFilePath );
#else
_splitpath( cpFilePath, szDrive, szPath, szFile, szExt );
sprintf( szFolder, "%s%s", szDrive, szPath );
SetCurrentDirectory( szFolder );
_AddFolderToZip( zipFile, szPath );
strcat( szFile, szExt );
_AddFileToZip( zipFile, szFile );
#endif
// Find next entry in \0\0 terminated string list
while( *cpFilePath )
{
cpFilePath++;
}
cpFilePath++;
}
}
__finally
{
if( NO_ERROR == zip_close( zipFile ) )
{
result = TRUE;
}
else
{
pze = zip_get_error( zipFile );
printf( "ZipTest> Failed to create output file '%s'...\n", szZipFileName );
printf( "ZipTest> libzip: %s\n", zip_strerror( zipFile ) );
printf( "ZipTest> zip_err = %d sys_err = %d\n", pze->zip_err, pze->sys_err );
}
}
SetCurrentDirectory( szStartPath );
return result;
}
我注意到了这一点, zip_file_add()
也会 zip_source_file()
返回成功错误代码。这种行为让我感到惊讶,如果您希望将其传达为失败,我理解这令人沮丧。
直接回答你的问题:
如何调试一个库的问题,即使它明显失败了,也会返回成功
如果有人认为库函数“明显失败”但它返回了成功代码,那么我会说有两种可能性:
使用开源库的好处是(理论上)您可以自己检查情况 1。从 记录的错误 和 源代码 ,我认为开发人员并不认为 \'fname\' 参数未指向文件时是故障模式。您甚至可以 向作者发送补丁来更新文档以使其更清晰。 而且他们似乎很活跃,所以可能会修复。
对于您的函数的问题,我会尝试测试该文件是否存在并且是否可读(您可以使用 fopen(fname, "r")
它)然后再尝试将其添加到存档中 zip_source_file()
.