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.harchive_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

  1. 下载Libarchive

    • 可以从Libarchive的官方网站(如GitHub上的libarchive仓库)下载最新版本的源代码。
    • 注意检查是否有预编译的Windows版本,这样可以节省编译时间。
  2. 编译Libarchive(如果下载的是源代码):

    • 在Windows上,通常可以使用Visual Studio或MinGW等编译器来编译Libarchive。
    • 需要按照Libarchive的编译说明进行操作,可能包括运行configure脚本(如果可用)、设置编译器选项等。
    • 编译完成后,会生成Libarchive的头文件(.h文件)和库文件(.lib.dll文件)。

2.2.2、配置开发环境

  1. 设置包含目录

    • 在你的C++项目中,需要设置包含Libarchive头文件的目录。这通常在IDE的项目设置中完成,例如Visual Studio的“项目属性”中的“C/C++”->“常规”->“附加包含目录”。
  2. 设置库目录

    • 同样,需要设置链接器(Linker)的附加库目录,以便编译器能够找到Libarchive的库文件。
  3. 添加库依赖

    • 在项目的链接器设置中添加Libarchive的库文件(.lib.dll),这通常在“链接器”->“输入”->“附加依赖项”中完成。

2.2.3 编写和编译代码

  1. 包含Libarchive头文件

    #include <archive.h>
    #include <archive_entry.h>
    
  2. 编写代码以使用Libarchive的功能

    • 根据你的需求,使用Libarchive提供的API来创建、读取或写入归档文件。
    • 例如,可以使用archive_read_new()来创建一个新的读取器对象,使用archive_read_support_format_all()来支持所有格式的归档文件,然后使用archive_read_open_filename()来打开归档文件。
  3. 编译代码

    • 使用你的C++编译器编译你的代码,确保链接了Libarchive库。
    • 如果遇到链接错误,检查是否所有必要的库都已正确添加,并检查库文件的路径是否正确。

2.2.4 注意事项

  1. 版本兼容性

    • 确保你下载的Libarchive版本与你的编译器和开发环境兼容。
  2. 依赖项

    • Libarchive可能依赖于其他库,如ZLIB、BZIP2等。确保这些依赖项也已正确安装并配置在你的项目中。
  3. 错误处理

    • Libarchive提供了丰富的错误处理机制。在编写代码时,要记得检查API调用的返回值,并适当处理错误情况。
  4. 性能优化

    • 如果需要处理大量数据或追求高性能,可以考虑调整Libarchive的配置选项或使用其高级功能。
  5. 文档和社区

    • 查阅Libarchive的官方文档以获取更详细的API信息和示例代码。
    • 参与Libarchive的社区讨论,以获取帮助和分享经验。

通过以上步骤,你应该能够在Windows上使用C++和Libarchive来处理归档和压缩文件了。

Linux使用C++生成光盘镜像文件通常需要借助第三方库,如`libarchive``boost filesystem`,它们提供了方便的功能来处理文件操作和创建ISO映像。以下是一个简单的步骤指南: 1. 安装必要的库: - 对于`libarchive`,可以使用`apt-get` (Debian/Ubuntu) `yum` (CentOS/RHEL) 安装: ```sh sudo apt-get install libarchive-dev # 者 yum sudo yum install libarchive-devel ``` 2. 包含库头文件并链接: 在C++源文件中添加`#include <archive.h>`和链接`-larchive`(如果使用g++): ```cpp #include <iostream> #include <archive/tar.h> // 使用libarchive int main() { // ... } g++ yourfile.cpp -o yourprogram -lz -laarchive ``` 3. 创建镜像文件: 你可以使用`std::ofstream`打开一个输出文件流,并结合`archive::TarWriter`从`libarchive`来创建ISO镜像。这里是一个简化的示例: ```cpp int main() { std::string output_path = "your_iso_image.iso"; std::ofstream archive_stream(output_path, std::ios::binary); if (!archive_stream) { std::cerr << "Failed to open the output file" << std::endl; return 1; } archive::TarWriter writer(archive_stream); const char* src_dir = "/path/to/source/directory"; // 替换为实际源目录 archive_entry entry; // 设置目录信息 memset(&entry, 0, sizeof(entry)); strncpy(entry.pathname, src_dir, PATH_MAX); entry.mode = S_IFDIR | 0555; // 目录权限 writer.add(&entry); // 添加目录到ISO // 遍历源目录并添加文件 // ... writer.finish(); // 结束写入 return 0; } ``` 4. 完成文件遍历并添加到ISO中。 注意:这只是一个基本框架,实际操作可能会更复杂,特别是当你需要处理目录结构、权限和时间戳等细节时。完成这个任务后,别忘了关闭所有文件流和archive实例。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

三雷科技

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值