C++解压及压缩(window或linux下编译、使用libarchive)
libarchive 是一个功能强大的库,用于创建、读取和提取各种归档格式,包括但不限于 ISO 9660、ZIP、TAR 等。虽然直接提供 libarchive 的 C++ 研发详细文档可能超出了简单回答的范围,但我可以基于一般的使用和研发经验,概述一些在 C++ 中使用 libarchive 的关键步骤和注意事项。
一、linux 系统 - 压缩解压
1.1 基础知识
1.1.1. 安装 libarchive
首先,你需要在你的系统上安装 libarchive 库。这通常可以通过包管理器(如 apt-get、yum 或 brew)或从源代码编译来完成。例如,在 Debian/Ubuntu 系统上,你可以使用以下命令安装:
sudo apt-get install libarchive-dev
注意:安装时可能需要选择安装 -dev
或 -devel
包,这些包包含了开发所需的头文件和库文件。
1.1.2. 包含头文件
在你的 C++ 代码中,你需要包含 libarchive 的头文件。通常,这包括 archive.h
和 archive_entry.h
,它们提供了操作归档的基本功能。
#include <archive.h>
#include <archive_entry.h>
1.1.3. 创建和使用 Archive 对象
libarchive 使用 struct archive
结构体来表示一个归档。你可以创建这个结构体的实例来读取或写入归档。
- 读取归档:使用
archive_read_new()
创建一个用于读取的归档对象。 - 写入归档:使用
archive_write_new()
创建一个用于写入的归档对象。
然后,你需要配置归档的格式(如 ISO9660、ZIP、TAR 等),并设置其他选项(如压缩方法)。
1.1.4. 打开和关闭归档
在读取或写入归档之前,你需要使用 archive_read_open_filename()
或 archive_write_open_filename()
(或类似函数)打开归档文件。操作完成后,使用 archive_read_close()
或 archive_write_close()
关闭归档。
1.1.5. 读取和写入归档条目
对于读取操作,你可以使用 archive_read_next_header()
读取归档中的下一个条目,并使用 archive_read_data()
读取条目的数据。
对于写入操作,你需要使用 archive_entry_new()
创建一个新的归档条目,并使用 archive_entry_set_*()
函数设置条目的属性(如文件名、大小、修改时间等)。然后,使用 archive_write_header()
写入条目头,并使用 archive_write_data()
写入条目数据。
1.1.6. 清理资源
完成归档操作后,不要忘记释放与归档对象相关联的所有资源。这通常涉及调用 archive_read_free()
或 archive_write_free()
来释放归档对象。
1.1.7. 编译和链接
在编译你的 C++ 程序时,需要确保链接了 libarchive 库。这通常通过向编译器添加 -larchive
选项来完成。
1.1.8. 错误处理
libarchive 提供了丰富的错误处理机制。你应该检查每个 libarchive 函数的返回值,并在发生错误时采取适当的措施。archive_errno()
和 archive_error_string()
函数可以用于获取有关错误的更多信息。
1.2 Linux C++ 压缩实例
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#include<fcntl.h>
#include"archive.h"
#include"archive_entry.h"
void write_archive(const char *outname, const char **filename) {
struct archive *a;
struct archive_entry *entry;
struct stat st;
char buff[1024];
int len;
int fd;
int ret;
a = archive_write_new();
archive_write_add_filter_gzip(a); // 添加gzip压缩
archive_write_set_format_pax_restricted(a); // 设置格式为pax_restricted,这通常是tar.gz格式的一部分
archive_write_open_filename(a, outname); // 打开输出文件
while (*filename) { // 遍历要压缩的文件列表
stat(*filename, &st); // 获取文件状态信息
entry = archive_entry_new(); // 创建新的归档条目
archive_entry_copy_pathname(entry, *filename); // 设置文件路径名
archive_entry_set_mtime(entry, st.st_mtime, 0); // 设置文件的修改时间
archive_entry_set_size(entry, st.st_size); // 设置文件大小
archive_entry_set_filetype(entry, AE_IFREG); // 设置文件类型为常规文件
archive_entry_set_perm(entry, 0644); // 设置文件权限
ret = archive_write_header(a, entry); // 写入归档头信息
if (ret != ARCHIVE_OK) { // 检查写入是否成功
printf("archive_write_header errno:%d, errstr:%s\n", a->error, archive_error_string(a)); // 输出错误信息
break; // 如果写入失败,则退出循环
}
// 在这里可以添加代码以实际写入文件内容到归档中(如果需要)
filename++; // 移动到下一个文件名
}
archive_write_close(a); // 关闭归档写入操作
archive_write_free(a); // 释放资源
}
1.3 Linux C++解压示例
#include <archive.h>
#include <archive_entry.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
void extract_tar_gz(const char *filename, const char *output_dir) {
struct archive *a;
struct archive_entry *entry;
int r;
// 创建归档读取器
a = archive_read_new();
archive_read_support_format_tar(a);
archive_read_support_filter_gzip(a);
// 打开归档文件
if (archive_read_open_filename(a, filename, 10240) != ARCHIVE_OK) {
fprintf(stderr, "Error opening archive file: %s\n", archive_error_string(a));
exit(EXIT_FAILURE);
}
// 遍历归档中的每个条目
while (archive_read_next_header(a, &entry) == ARCHIVE_OK) {
const char *pathname = archive_entry_pathname(entry);
mode_t mode = archive_entry_mode(entry);
// 跳过目录(如果你需要解压目录内的文件,请保留此部分)
if (S_ISDIR(mode)) {
mkdir(pathname, 0755);
continue;
}
// 创建输出文件的路径
char output_path[1024];
snprintf(output_path, sizeof(output_path), "%s/%s", output_dir, pathname);
// 确保输出目录存在
char *dir = strdup(output_path);
char *last_slash = strrchr(dir, '/');
if (last_slash) {
*last_slash = '\0';
mkdir_p(dir); // 注意:mkdir_p是一个自定义函数,用于递归创建目录
*last_slash = '/';
}
free(dir);
// 提取文件
int fd = open(output_path, O_WRONLY | O_CREAT | O_TRUNC, mode);
if (fd == -1) {
perror("open");
continue;
}
la_ssize_t size;
const void *buff;
while (archive_read_data_block(a, &buff, &size) == ARCHIVE_OK) {
write(fd, buff, size);
}
close(fd);
}
// 关闭归档
archive_read_free(a);
}
// 自定义函数:递归创建目录
int mkdir_p(const char *path) {
struct stat st = {0};
char _path[PATH_MAX];
char *p = NULL;
size_t len;
snprintf(_path, sizeof(_path), "%s", path);
len = strlen(_path);
if (_path[len - 1] == '/')
_path[len - 1] = 0;
for (p = _path + 1; *p; p++)
if (*p == '/') {
*p = 0;
if (stat(_path, &st) != 0)
if (mkdir(_path, 0755) != 0) {
perror("mkdir");
return -1;
}
*p = '/';
}
if (stat(_path, &st) != 0)
if (mkdir(_path, 0755) != 0) {
perror("mkdir");
return -1;
}
return 0;
}
int main(int argc, char **argv) {
if (argc != 3) {
fprintf(stderr, "Usage: %s <tar.gz_file> <output_directory>\n", argv[0]);
return EXIT_FAILURE;
}
extract_tar_gz(argv[1], argv[2]);
return EXIT_SUCCESS;
}
二、window系统C++压缩解压
在Windows上使用Libarchive进行C++开发时,需要关注几个关键步骤,包括安装Libarchive、配置开发环境以及编写和编译代码。以下是一个详细的指南:
2.2 基础知识
2.2.1、安装Libarchive
-
下载Libarchive:
- 可以从Libarchive的官方网站(如GitHub上的libarchive仓库)下载最新版本的源代码。
- 注意检查是否有预编译的Windows版本,这样可以节省编译时间。
-
编译Libarchive(如果下载的是源代码):
- 在Windows上,通常可以使用Visual Studio或MinGW等编译器来编译Libarchive。
- 需要按照Libarchive的编译说明进行操作,可能包括运行
configure
脚本(如果可用)、设置编译器选项等。 - 编译完成后,会生成Libarchive的头文件(
.h
文件)和库文件(.lib
或.dll
文件)。
2.2.2、配置开发环境
-
设置包含目录:
- 在你的C++项目中,需要设置包含Libarchive头文件的目录。这通常在IDE的项目设置中完成,例如Visual Studio的“项目属性”中的“C/C++”->“常规”->“附加包含目录”。
-
设置库目录:
- 同样,需要设置链接器(Linker)的附加库目录,以便编译器能够找到Libarchive的库文件。
-
添加库依赖:
- 在项目的链接器设置中添加Libarchive的库文件(
.lib
或.dll
),这通常在“链接器”->“输入”->“附加依赖项”中完成。
- 在项目的链接器设置中添加Libarchive的库文件(
2.2.3 编写和编译代码
-
包含Libarchive头文件:
#include <archive.h> #include <archive_entry.h>
-
编写代码以使用Libarchive的功能:
- 根据你的需求,使用Libarchive提供的API来创建、读取或写入归档文件。
- 例如,可以使用
archive_read_new()
来创建一个新的读取器对象,使用archive_read_support_format_all()
来支持所有格式的归档文件,然后使用archive_read_open_filename()
来打开归档文件。
-
编译代码:
- 使用你的C++编译器编译你的代码,确保链接了Libarchive库。
- 如果遇到链接错误,检查是否所有必要的库都已正确添加,并检查库文件的路径是否正确。
2.2.4 注意事项
-
版本兼容性:
- 确保你下载的Libarchive版本与你的编译器和开发环境兼容。
-
依赖项:
- Libarchive可能依赖于其他库,如ZLIB、BZIP2等。确保这些依赖项也已正确安装并配置在你的项目中。
-
错误处理:
- Libarchive提供了丰富的错误处理机制。在编写代码时,要记得检查API调用的返回值,并适当处理错误情况。
-
性能优化:
- 如果需要处理大量数据或追求高性能,可以考虑调整Libarchive的配置选项或使用其高级功能。
-
文档和社区:
- 查阅Libarchive的官方文档以获取更详细的API信息和示例代码。
- 参与Libarchive的社区讨论,以获取帮助和分享经验。
通过以上步骤,你应该能够在Windows上使用C++和Libarchive来处理归档和压缩文件了。