tar(tape archive)是Unix和类Unix系统上文件打包工具,可以将多个文件合并为一个文件,使用tar工具打出来的包称为tar包。一般打包后的文件名后缀为”.tar”,也可以为其它。tar代表未被压缩的tar文件,已被压缩的tar文件则追加压缩文件的扩展名,如经过gzip压缩后的tar文件,扩展名为”.tar.gz”。在windows系统中用WinRAR也可以解压缩打开tar包。tar文件格式已经成为POSIX标准,最初是POSIX.1-1998,目前是POSIX.1-2001.

tar中的数据都是以512字节为单位。tar由两部分组成即头部+内容,其中头部是512字节的头部结构,内容是存放一个文件内容的地方。

tar文件格式的详细介绍可以参考:https://en.wikipedia.org/wiki/Tar_(computing)#File_header

通过执行以下命令生成测试tar包:

tar -cvf test.tar *

test.tar中包含两个文件blog_info.txt和github_info.txt.

其中blog_info.txt文件内容如下:

name: fengbingchun
address: http://blog.csdn.net/fengbingchun?viewmode=contents

github_info.txt文件内容如下:

name: fengbingchun
address: https://github.com/fengbingchun

实现代码tar.hpp:

#ifndef FBC_MESSY_TEST_TAR_HPP_
#define FBC_MESSY_TEST_TAR_HPP_#include <vector>
#include <string>/* reference:http://www.gnu.org/software/tar/manual/html_node/Standard.htmlhttp://stackoverflow.com/questions/2505042/how-to-parse-a-tar-file-in-chttp://directory.fsf.org/wiki/Libtarhttp://work.freenet59.ru/svn/pkgsrc_haiku/trunk/archivers/libarchive/files/contrib/untar.chttps://codeistry.wordpress.com/2014/08/14/how-to-parse-a-tar-file/http://stackoverflow.com/questions/17862383/how-to-know-the-files-inside-the-tar-parserhttps://en.wikipedia.org/wiki/Tar_(computing)
*//* tar Header Block, from POSIX 1003.1-1990.  *//* POSIX header.  */typedef struct posix_header
{                                     /* byte offset */char name[100];               /*   0 */char mode[8];                 /* 100 */char uid[8];                  /* 108 */char gid[8];                  /* 116 */char size[12];                /* 124 */char mtime[12];               /* 136 */char chksum[8];               /* 148 */char typeflag;                /* 156 */char linkname[100];           /* 157 */char magic[6];                /* 257 */char version[2];              /* 263 */char uname[32];               /* 265 */char gname[32];               /* 297 */char devmajor[8];             /* 329 */char devminor[8];             /* 337 */char prefix[155];             /* 345 *//* 500 */
} tar_posix_header;/*location  size  field0         100   File name100       8     File mode108       8     Owner's numeric user ID116       8     Group's numeric user ID124       12    File size in bytes136       12    Last modification time in numeric Unix time format148       8     Checksum for header block156       1     Link indicator (file type)157       100   Name of linked file
*/#define TMAGIC   "ustar"        /* ustar and a null */
#define TMAGLEN  6
#define TVERSION "00"           /* 00 and no null */
#define TVERSLEN 2/* Values used in typeflag field.  */
#define REGTYPE  '0'            /* regular file */
#define AREGTYPE '\0'           /* regular file */
#define LNKTYPE  '1'            /* link */
#define SYMTYPE  '2'            /* reserved */
#define CHRTYPE  '3'            /* character special */
#define BLKTYPE  '4'            /* block special */
#define DIRTYPE  '5'            /* directory */
#define FIFOTYPE '6'            /* FIFO special */
#define CONTTYPE '7'            /* reserved */class TarFile {
public:TarFile(const char* tar_name);bool IsValidTarFile();std::vector<std::string> GetFileNames();bool GetFileContents(const char* file_name, char* contents);size_t GetFileSize(const char* file_name);size_t GetTarSize();~TarFile();
private:FILE* file;size_t size;std::vector<std::string> file_names;std::vector<size_t> file_sizes;std::vector<size_t> file_data_start_addrs;
};int test_tar();#endif // FBC_MESSY_TEST_TAR_HPP_

tar.cpp:

#include "tar.hpp"TarFile::TarFile(const char* tar_name): file(nullptr), size(0)
{file_names.clear();file_sizes.clear();file_data_start_addrs.clear();file = fopen(tar_name, "rb");
}TarFile::~TarFile()
{if (file) {fclose(file);file = nullptr;}file_names.clear();file_sizes.clear();file_data_start_addrs.clear();
}bool TarFile::IsValidTarFile()
{if (!file) return false;const int block_size{ 512 };unsigned char buf[block_size];tar_posix_header* header = (tar_posix_header*)buf;memset(buf, 0, block_size);fseek(file, 0, SEEK_END);size = ftell(file);fseek(file, 0, SEEK_SET);if (size % block_size != 0) {fprintf(stderr, "tar file size should be a multiple of 512 bytes: %d\n", size);return false;}size_t pos{ 0 };while (1) {size_t read_size = fread(buf, block_size, 1, file);if (read_size != 1) break;if (strncmp(header->magic, TMAGIC, 5)) break;pos += block_size;size_t file_size{0};sscanf(header->size, "%lo", &file_size);size_t file_block_count = (file_size + block_size - 1) / block_size;switch (header->typeflag) {case '0': // intentionally dropping throughcase '\0':// normal filefile_sizes.push_back(file_size);file_names.push_back(std::string(header->name));file_data_start_addrs.push_back(pos);break;case '1':// hard linkbreak;case '2':// symbolic linkbreak;case '3':// device file/special filebreak;case '4':// block devicebreak;case '5':// directorybreak;case '6':// named pipebreak;default:break;}pos += file_block_count * block_size;fseek(file, pos, SEEK_SET);}fseek(file, 0, SEEK_SET);return true;
}std::vector<std::string> TarFile::GetFileNames()
{return file_names;
}bool TarFile::GetFileContents(const char* file_name, char* contents)
{bool flag = false;for (int i = 0; i < file_names.size(); i++) {std::string name_(file_name);if (file_names[i].compare(name_) == 0) {int file_size = file_sizes[i];flag = true;fseek(file, file_data_start_addrs[i], SEEK_SET);fread(contents, file_size, 1, file);fseek(file, 0, SEEK_SET);break;}}return flag;
}size_t TarFile::GetFileSize(const char* file_name)
{size_t file_size{0};for (int i = 0; i < file_names.size(); i++) {std::string name_(file_name);if (file_names[i].compare(name_) == 0) {file_size = file_sizes[i];break;}}return file_size;
}size_t TarFile::GetTarSize()
{return size;
}//
int test_tar()
{const std::string tar_file_path{ "E:/GitCode/Messy_Test/testdata/test.tar" };TarFile tarfile(tar_file_path.c_str());bool is_valid_tar_file = tarfile.IsValidTarFile();if (!is_valid_tar_file) {fprintf(stderr, "it is not a valid tar file: %s\n", tar_file_path.c_str());return -1;}fprintf(stderr, "tar file size: %d byte\n", tarfile.GetTarSize());std::vector<std::string> file_names = tarfile.GetFileNames();fprintf(stderr, "tar file count: %d\n", file_names.size());for (auto name : file_names) {fprintf(stderr, "=====================================\n");size_t file_size = tarfile.GetFileSize(name.c_str());fprintf(stderr, "file name: %s,  size: %d byte\n", name.c_str(), file_size);char* contents = new char[file_size + 1];tarfile.GetFileContents(name.c_str(), contents);contents[file_size] = '\0';fprintf(stderr, "contents:\n%s\n", contents);delete[] contents;}return 0;
}

测试结果如下:

GitHub:https://github.com/fengbingchun/Messy_Test

C++实现tar包解析相关推荐

  1. [Linux运维基础]全家桶详解!Linux中RPM包、wget下载、YUM安装、tar包、zip等包管理方式区别与参数详解,附wget下载源码包编译安装方法

    文章目录 一.RPM.tar.gz 1.rpm包格式 2.rpm包管理 3.tar包管理参数 二.wget 1.wget参数 2.wget下载源码包后编译安装 三.YUM 1.YUM工作原理 2. Y ...

  2. python 解压缩 tar 包 或 tar.gz包

    python 解压缩 tar 包 或 tar.gz包 # pip install rarfile import tarfile def decompression_tar(tar_path, file ...

  3. Linux编译mybatis,使用mybatis assembly插件打成tar包,在linux系统中运行服务-Go语言中文社区...

    使用mybatis assembly插件打成tar包,在linux系统中运行服务 assembly插件插件地址: 链接:https://pan.baidu.com/s/1i6bWPxF 密码:gad5 ...

  4. 关于vivo 8.0和miui新系统android studio调试出现“包解析错误”的bug的解决办法

    最近在工作中遇到了调试的时候将app安装到vivo 手机上,出现了包解析错误的问题.一般来说这种问题只会出现在手机版本 小于 app所要求的最低版本的手机上.但是此vivo手机的版本是8.0,很显然不 ...

  5. SSL加密包解析的几个概念梳理

    1.DPI技术初识 DPI(Deep PacketInspection)深度包检测技术是在传统IP数据包检测技术(OSI L2-L4之间包含的数据包元素的检测分析)之上增加了对应用层数据的应用协议识别 ...

  6. 使用Golang flag包解析字符串

    本篇文章主要介绍如何使用flag包解析字符串,没有介绍flag包的详细使用,需要学习flag包如何使用的同学可以参考如下这篇文章: Go语言中使用flag包对命令行进行参数解析的方法 https:// ...

  7. centos 7使用tar包安装ansible

    由于我的yum源没有ansible软件包,防止以后内网服务器也没有ansible的yum源,干脆一点,直接tar包安装!!!! 下载软件包 - # 1.python安装 # python2.7安装 [ ...

  8. linux下tar包追加与其他压缩追加方式

    前提:公司日志文件每天产生几十G又不能删,而且要保存半年:那就只能压缩,但文件是每天一加的,那就只能在压缩文件中添加/更新文件? 目录 1.tar包解决的问题 2.Linux zip命令 语法 zip ...

  9. 蓝牙4.0BLE抓包(二) – 广播包解析

    转自: http://www.cnblogs.com/aikm/p/5022502.html 版权声明:本文为博主原创文章,转载请注明作者和出处.    作者:强光手电[艾克姆科技-无线事业部] 在使 ...

最新文章

  1. System Center 2012 r2优点
  2. GitHub 热榜:来膜拜这个流弊的 AI 框架!
  3. 工程能力提升管理之道
  4. 窗函数-减少傅里叶变换泄漏
  5. 基于 abp vNext 和 .NET Core 开发博客项目 - Blazor 实战系列(四)
  6. CF183C:Diverse Permutation(构造)
  7. GO 从零开始的语法学习二
  8. C++学习之路:适合C++新手的练手项目,高薪之路必备项目!
  9. 3.使用Selenium模拟浏览器抓取淘宝商品美食信息
  10. python Linux系统信息
  11. 【Pytorch】 .item()==>得到元素张量里面的一个元素值,便可以循环、查看...操作
  12. PyQt5笔记(01) -- 创建空白窗体
  13. WebFlux响应式编程基础之 5 webflux服务端开发讲解
  14. web端 微软 RDLC 报表插件 宽大于高 横向打印失效 解决方案
  15. Docker学习文档之三 其他相关-参考
  16. 《矩阵与变换》教学中的几个“务必”
  17. XP系统下如何把FAT32转换成NTFS格式的?
  18. 2.支付平台架构:业务、规划、设计与实现 --- 收银台系统
  19. 2019年上半年计算机水平,2019年上半年全国计算机等级考试通过秘诀分享
  20. centos7安装其他源以及安装软件

热门文章

  1. VS上配置opencv249所添加的附加依赖项
  2. sysfs_create_dir_ns
  3. Opencv-python 图像处理基础知识
  4. OpenCV(六)形态学操作1--基础:膨胀与腐蚀(回调函数)
  5. groovy怎样从sql语句中截取表名_SQL常用的基础查询语句
  6. VSCode设置类似Webstorm那样可以用本地局域网IP地址访问自己开发的测试项目,vs code 前端如何以服务器模式打开?
  7. 在Ubuntu 14.04 64bit上下载更新x265源码
  8. Blender赛车动画制作学习教程 Learn Race Car Animation with Blender
  9. Cmake 实例学习 一
  10. Typedef用法(转载)