I use libarchive to create a archive, and the source is a directory, I need create the archive with the same directory tree of the source directory, so I use the archive_read_disk_open and archive_read_disk_descend, but when i create a file with archive_write_open_filename(a, "xxx.zip"),there is always only a "xxx" file in the result zip file, I have to extract the "xxx" file and then rename the "xxx" to "xxx.zip", then I get the correct zip file
If I read entry from the xxx.zip using libarchive, I can get the correct directory tree.
This is the C++ code I use to create the zip file:
bool KArchiveManager::pack(const QString& srcDirPath)
{
struct archive* a;
struct archive_entry* entry;
int r;
a = archive_write_new();
archive_write_set_format_zip(a);
archive_write_set_compression_compress(a);
QString outPath= srcDirPath + ".zip";
r = archive_write_open_filename_w(a, outPath.toStdWString().c_str());
if (r != ARCHIVE_OK)
{
QString msg = QString("archive_write_open_filename_w : %1")
.arg(archive_error_string(a));
emit packArchiveError(msg);
archive_write_close(a);
archive_write_free(a);
return false;
}
QDir compressDir(srcDirPath);
if (!compressDir.exists())
{
emit packArchiveError(tr("compress dir not exist"));
archive_write_close(a);
archive_write_free(a);
return false;
}
QStringList entryList = compressDir.entryList(
QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot);
foreach(const QString & entryName, entryList)
{
struct archive* disk = archive_read_disk_new();
archive_read_disk_set_standard_lookup(disk);
QString diskPath = compressDir.absoluteFilePath(entryName);
r = archive_read_disk_open(disk, diskPath.toStdString().c_str());
if (r != ARCHIVE_OK)
{
QString msg = QString("archive_read_disk_open : %1")
.arg(archive_error_string(disk));
emit packArchiveError(msg);
archive_write_close(a);
archive_write_free(a);
archive_read_close(disk);
archive_read_free(disk);
return false;
}
while (true)
{
entry = archive_entry_new();
r = archive_read_next_header(disk, &entry);
if (r == ARCHIVE_EOF)
break;
if (r != ARCHIVE_OK)
{
QString msg = QString("archive_read_next_header : %1")
.arg(archive_error_string(disk));
emit packArchiveError(msg);
archive_write_close(a);
archive_write_free(a);
archive_read_close(disk);
archive_read_free(disk);
return false;
}
archive_read_disk_descend(disk);
QString sourcePath = archive_entry_pathname(entry);
QString pathName = sourcePath.mid(srcDirPath.size() + 1);
archive_entry_set_pathname(entry, pathName.toLocal8Bit());
r = archive_write_header(a, entry);
if (r != ARCHIVE_OK)
{
QString msg = QString("archive_write_header : %1")
.arg(archive_error_string(a));
emit packArchiveError(msg);
archive_write_close(a);
archive_write_free(a);
archive_read_close(disk);
archive_read_free(disk);
return false;
}
//copydata
if (archive_entry_filetype(entry) != AE_IFDIR)
{
QFile file(sourcePath);
if (file.open(QIODevice::ReadOnly))
{
QDataStream in(&file);
while (!in.atEnd())
{
QByteArray chunk = file.read(1024);
archive_write_data(a, chunk.data(), chunk.size());
}
file.close();
}
}
archive_entry_free(entry);
}
archive_read_close(disk);
archive_read_free(disk);
}
archive_write_close(a);
archive_write_free(a);
return true;
}
How can I create the correct zip file instead of a zip file always contain the same name file of the param passed to the archive_write_open_filename?
Run
cmd.exe, within that use thecdcommand to navigate to the correct directory, then run thedircommand, and check the filename in the output. It will bexxx.zip.Some file managers such as Explorer hide the extension (
.zipin this case). You can configure them to show the extension.