C++实现tar包解析
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
相关文章:

HTML5的学习,各个标签的尝试
style标签的使用可以更好的改变各个标题风格 基本标签<p>,标题<h>,这里br是换行。 超链接的使用,属性href。 表格的使用table。 最后就是图片 img,和音频audio插入地址即可。 今天的学习就分享这些,谢谢大家。转载于:https://www…

Android获取内部和SDCard的存储空间
有时我们开Android项目开发时会用到文件存储或上传文件的一些操作,那么我们前提是要获取到该存储设备的大小,以方便于与我们需要操作的文件的大小做比较,如果操作的文件大小小于存储空间,那么就可以继续操作,反之则不能…

排序算法 Java实现
选择排序 核心思想 选择最小元素,与第一个元素交换位置;剩下的元素中选择最小元素,与当前剩余元素的最前边的元素交换位置。 分析 选择排序的比较次数与序列的初始排序无关,比较次数都是N(N-1)/2。 移动次数最多只有n-1次。 因此&…

正则表达式简介及在C++11中的简单使用
正则表达式(regular expression)是计算机科学中的一个概念,又称规则表达式,通常简写为regex、regexp、RE、regexps、regexes、regexen。 正则表达式是一种文本模式。正则表达式是强大、便捷、高效的文本处理工具。正则表达式本身,加上如同一…

经典再读 | NASNet:神经架构搜索网络在图像分类中的表现
(图片付费下载于视觉中国)作者 | Sik-Ho Tsang译者 | Rachel编辑 | Jane出品 | AI科技大本营(ID:rgznai100)【导读】从 AutoML 到 NAS,都是企业和开发者的热门关注技术,以往我们也分享了很多相关…

javascript面向对象技术基础(二)
数组我们已经提到过,对象是无序数据的集合,而数组则是有序数据的集合,数组中的数据(元素)通过索引(从0开始)来访问,数组中的数据可以是任何的数据类型.数组本身仍旧是对象,但是由于数组的很多特性,通常情况下把数组和对象区别开来分别对待(Throughout this book, objects and a…

MediaPipe:Google Research 开源的跨平台多媒体机器学习模型应用框架
作者 | MediaPipe 团队来源 | TensorFlow(ID:tensorflowers)【导读】我爱计算机视觉(aicvml)CV君推荐道:“虽然它是出自Google Research,但不是一个实验品,而是已经应用于谷歌多款产…

机器学习研究的七个迷思
作者 Oscar Chang 总结了机器学习研究中的七大迷思,每个问题都很有趣,也可能是你在研究机器学习的过程中曾经遇到过的“想当然”问题。AI 前线对这篇文章进行了编译,以飨读者。迷思之一:TensorFlow 是张量操作库 它实际上就是一个…
Caffe源码中common文件分析
Caffe源码(caffe version:09868ac , date: 2015.08.15)中的一些重要头文件如caffe.hpp、blob.hpp等或者外部调用Caffe库使用时,一般都会include<caffe/common.hpp>文件,下面分析此文件的内容:1. include的文件:boost中…
编程乐趣:C#彻底删除文件
经常用360的文件粉碎,删除隐私文件貌似还不错的。不过C#也可以实现彻底删除文件。试了下用360文件恢复恢复不了源文件了。代码如下:public class AbsoluteFile{public event EventHandler FinishDeleteFileEvent null;public event EventHandler Finish…

大数据工程师手册:全面系统的掌握必备知识与工具
作者 | Phoebe Wong译者 | 陆离编辑 | Jane出品 | AI科技大本营(ID:rgznai100)前言如何才能成为一名真正的“全栈(full-stack)”数据科学家?需要了解哪些知识?掌握哪些技能?概括来讲…

JSON.stringify()
写在前边 不言而喻,JSON.stringify() 是用来将合法的JSON数据字符串化的!然而在正常的工作中我们用到的只是最基础的功能;今天我们就探索不一样的JSON.stringify()。 基础用法 基本数据类型 JSON.stringify(2) // "2" JSON.stringi…

C++中前置声明介绍
前置声明是指对类、函数、模板或者结构体进行声明,仅仅是声明,不包含相关具体的定义。在很多场合我们可以用前置声明来代替#include语句。类的前置声明只是告诉编译器这是一个类型,但无法告知类型的大小,成员等具体内容。在未提供…

在Java SE中使用Hibernate处理数据
如今,Hibernate正在迅速成为非常流行的(如果不是最流行的)J2EE O/R映射程序/数据集成框架。它为开发人员提供了处理企业中的关系数据库的整洁、简明且强大的工具。但如果外部需要访问这些已被包装在J2EE Web应用程序中的实体又该怎么办&#…

利用OpenCV、Python和Ubidots构建行人计数器程序(附完整代码)
作者 | Jose Garcia译者 | 吴振东校对 | 张一豪、林亦霖,编辑 | 于腾凯来源 | 数据派(ID:datapi)导读:本文将利用OpenCV,Python和Ubidots来编写一个行人计数器程序,并对代码进行了较为详细的讲解…
开源软件License汇总
开源软件英文为Open Source Software,简称OSS,又称开放源代码软件,是一种源代码可以任意获取的计算机软件,这种软件的著作权持有人在软件协议的规定之下保留一部分权利并允许用户学习、修改以及以任何目的向任何人分发该软件。 某…

前深度学习时代CTR预估模型的演化之路:从LR到FFM\n
本文是王喆在 AI 前线 开设的原创技术专栏“深度学习 CTR 预估模型实践”的第二篇文章(以下“深度学习 CTR 预估模型实践”简称“深度 CTR 模型”)。专栏第一篇文章回顾:《深度学习CTR预估模型凭什么成为互联网增长的关键?》。重看…

神器与经典--sp_helpIndex
每每和那些NB的人学习技术的时候,往往都佩服他们对各个知识点都熟捻于心,更佩服的是可以在很短时间找出很多业界大师写的文章和开发的工具,就像机器猫的口袋,让人羡慕嫉妒恨啊!宋沄剑宋桑就是其中之一,打劫其硬盘的念头已计划很久,只待时机成…

评分9.7!这本Python书彻底玩大了?程序员:真香!
「超级星推官/每周分享」是一个围绕程序员生活、学习相关的推荐栏目。CSDN出品,每周发布,暂定5期。关键词:靠谱!优质!本期内容,我们将抽1人送出由我司程序员奉为“超级神作”的《疯狂Python讲义》1本&#…

Caffe源码中caffe.proto文件分析
Caffe源码(caffe version:09868ac , date: 2015.08.15)中有一些重要文件,这里介绍下caffe.proto文件。在src/caffe/proto目录下有一个caffe.proto文件。proto目录下除了caffe.proto文件外,还有caffe.pb.h和caffe.pb.cc两个文件,此两个文件是根…

这套完美的Java环境安装教程,完整,详细,清晰可观,让你一目了然,简单易懂。⊙﹏⊙...
JDK下载与安装教程 2017年06月18日 22:53:16 Danishlyy1995 阅读数:349980版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u012934325/article/details/73441617学习JAVA,必须得安装一下JDK(java dev…

【畅谈百度轻应用】云时代·轻应用·大舞台
云时代轻应用大舞台刘志勇君不见,上下班的地铁上,低头看手机;同事吃饭聊天,低头看手机;甚至朋友聚会,忙里偷闲打个招呼,然后继续低头看手机。正如微博上一个流传甚广的段子:“世界上…

如何画出高级酷炫的神经网络图?优秀程序员都用了这几个工具
(图片付费下载于视觉中国)作者 | 言有三 来源 | 有三AI(ID:yanyousan_ai)【导读】本文我们聊聊如何才能画出炫酷高大上的神经网络图,下面是常用的几种工具。1、NN-SVGNN-SVG 可以非常方便的画出各种类型的…
OpenBLAS简介及在Windows7 VS2013上源码的编译过程
OpenBLAS(Open Basic Linear Algebra Subprograms)是开源的基本线性代数子程序库,是一个优化的高性能多核BLAS库,主要包括矩阵与矩阵、矩阵与向量、向量与向量等操作。它的License是BSD-3-Clause,可以商用,目前最新的发布版本是0.…

技本功丨请带上纸笔刷着看:解读MySQL执行计划的type列和extra列
本萌最近被一则新闻深受鼓舞,西工大硬核“女学神”白雨桐,获6所世界顶级大学博士录取通知书。货真价值的才貌双全,别人家的孩子高考失利与心仪的专业失之交臂,选择了软件工程这门自己完全不懂的专业.即便全部归零,也要…

精美素材分享:16套免费的扁平化图标下载
在这篇文章中你可以看到16套华丽的扁平化图标素材,对于设计师来说非常有价值,能够帮助他们节省大量的时间。这些精美的扁平化图标可用于多种用途,如:GUI 设计,印刷材料,WordPress 主题,演示&…
Caffe源码中math_functions文件分析
Caffe源码(caffe version:09868ac , date: 2015.08.15)中有一些重要文件,这里介绍下math_functions文件。1. include文件:(1)、<glog/logging.h>:GLog库,它是google的一个开源的日志库,其使用可以参考&…

论文推荐 | 目标检测中不平衡问题算法综述
(图片付费下载于视觉中国)作者 | CV君来源 | 我爱计算机视觉(ID:aicvml)今天跟大家推荐一篇前几天新出的投向TPAMI的论文:Imbalance Problems in Object Detection: A Review,作者详细考察了目标…

php使用redis的GEO地理信息类型
redis3.2中增中了对GEO类型的支持,该类型存储经纬度,提供了经纬设置,查询,范围查询,距离查询,经纬度hash等操作。 <?php$redis new Redis(); $redis->connect(127.0.0.1, 6379, 60); $redis->au…
Caffe源码中syncedmem文件分析
Caffe源码(caffe version:09868ac , date: 2015.08.15)中有一些重要文件,这里介绍下syncedmem文件。1. include文件:(1)、<caffe/common.hpp>:此文件的介绍可以参考:http://blog.csdn.net/fengbingchun/article/detail…