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包:

  1. tar -cvf test.tar *

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

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

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

github_info.txt文件内容如下:

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

实现代码tar.hpp:

  1. #ifndef FBC_MESSY_TEST_TAR_HPP_
  2. #define FBC_MESSY_TEST_TAR_HPP_
  3.  
  4. #include <vector>
  5. #include <string>
  6.  
  7. /* reference:
  8. http://www.gnu.org/software/tar/manual/html_node/Standard.html
  9. http://stackoverflow.com/questions/2505042/how-to-parse-a-tar-file-in-c
  10. http://directory.fsf.org/wiki/Libtar
  11. http://work.freenet59.ru/svn/pkgsrc_haiku/trunk/archivers/libarchive/files/contrib/untar.c
  12. https://codeistry.wordpress.com/2014/08/14/how-to-parse-a-tar-file/
  13. http://stackoverflow.com/questions/17862383/how-to-know-the-files-inside-the-tar-parser
  14. https://en.wikipedia.org/wiki/Tar_(computing)
  15. */
  16.  
  17. /* tar Header Block, from POSIX 1003.1-1990. */
  18.  
  19. /* POSIX header. */
  20.  
  21. typedef struct posix_header
  22. { /* byte offset */
  23. char name[100]; /* 0 */
  24. char mode[8]; /* 100 */
  25. char uid[8]; /* 108 */
  26. char gid[8]; /* 116 */
  27. char size[12]; /* 124 */
  28. char mtime[12]; /* 136 */
  29. char chksum[8]; /* 148 */
  30. char typeflag; /* 156 */
  31. char linkname[100]; /* 157 */
  32. char magic[6]; /* 257 */
  33. char version[2]; /* 263 */
  34. char uname[32]; /* 265 */
  35. char gname[32]; /* 297 */
  36. char devmajor[8]; /* 329 */
  37. char devminor[8]; /* 337 */
  38. char prefix[155]; /* 345 */
  39. /* 500 */
  40. } tar_posix_header;
  41.  
  42. /*
  43. location size field
  44. 0 100 File name
  45. 100 8 File mode
  46. 108 8 Owner's numeric user ID
  47. 116 8 Group's numeric user ID
  48. 124 12 File size in bytes
  49. 136 12 Last modification time in numeric Unix time format
  50. 148 8 Checksum for header block
  51. 156 1 Link indicator (file type)
  52. 157 100 Name of linked file
  53. */
  54.  
  55. #define TMAGIC "ustar" /* ustar and a null */
  56. #define TMAGLEN 6
  57. #define TVERSION "00" /* 00 and no null */
  58. #define TVERSLEN 2
  59.  
  60. /* Values used in typeflag field. */
  61. #define REGTYPE '0' /* regular file */
  62. #define AREGTYPE '\0' /* regular file */
  63. #define LNKTYPE '1' /* link */
  64. #define SYMTYPE '2' /* reserved */
  65. #define CHRTYPE '3' /* character special */
  66. #define BLKTYPE '4' /* block special */
  67. #define DIRTYPE '5' /* directory */
  68. #define FIFOTYPE '6' /* FIFO special */
  69. #define CONTTYPE '7' /* reserved */
  70.  
  71. class TarFile {
  72. public:
  73. TarFile(const char* tar_name);
  74. bool IsValidTarFile();
  75. std::vector<std::string> GetFileNames();
  76. bool GetFileContents(const char* file_name, char* contents);
  77. size_t GetFileSize(const char* file_name);
  78. size_t GetTarSize();
  79. ~TarFile();
  80. private:
  81. FILE* file;
  82. size_t size;
  83. std::vector<std::string> file_names;
  84. std::vector<size_t> file_sizes;
  85. std::vector<size_t> file_data_start_addrs;
  86. };
  87.  
  88. int test_tar();
  89.  
  90. #endif // FBC_MESSY_TEST_TAR_HPP_

tar.cpp:

  1. #include "tar.hpp"
  2.  
  3. TarFile::TarFile(const char* tar_name)
  4. : file(nullptr), size(0)
  5. {
  6. file_names.clear();
  7. file_sizes.clear();
  8. file_data_start_addrs.clear();
  9. file = fopen(tar_name, "rb");
  10. }
  11.  
  12. TarFile::~TarFile()
  13. {
  14. if (file) {
  15. fclose(file);
  16. file = nullptr;
  17. }
  18. file_names.clear();
  19. file_sizes.clear();
  20. file_data_start_addrs.clear();
  21. }
  22.  
  23. bool TarFile::IsValidTarFile()
  24. {
  25. if (!file) return false;
  26.  
  27. const int block_size{ 512 };
  28. unsigned char buf[block_size];
  29. tar_posix_header* header = (tar_posix_header*)buf;
  30. memset(buf, 0, block_size);
  31.  
  32. fseek(file, 0, SEEK_END);
  33. size = ftell(file);
  34. fseek(file, 0, SEEK_SET);
  35. if (size % block_size != 0) {
  36. fprintf(stderr, "tar file size should be a multiple of 512 bytes: %d\n", size);
  37. return false;
  38. }
  39.  
  40. size_t pos{ 0 };
  41.  
  42. while (1) {
  43. size_t read_size = fread(buf, block_size, 1, file);
  44. if (read_size != 1) break;
  45. if (strncmp(header->magic, TMAGIC, 5)) break;
  46.  
  47. pos += block_size;
  48. size_t file_size{0};
  49. sscanf(header->size, "%lo", &file_size);
  50. size_t file_block_count = (file_size + block_size - 1) / block_size;
  51.  
  52. switch (header->typeflag) {
  53. case '0': // intentionally dropping through
  54. case '\0':
  55. // normal file
  56. file_sizes.push_back(file_size);
  57. file_names.push_back(std::string(header->name));
  58. file_data_start_addrs.push_back(pos);
  59. break;
  60. case '1':
  61. // hard link
  62. break;
  63. case '2':
  64. // symbolic link
  65. break;
  66. case '3':
  67. // device file/special file
  68. break;
  69. case '4':
  70. // block device
  71. break;
  72. case '5':
  73. // directory
  74. break;
  75. case '6':
  76. // named pipe
  77. break;
  78. default:
  79. break;
  80. }
  81.  
  82. pos += file_block_count * block_size;
  83. fseek(file, pos, SEEK_SET);
  84. }
  85.  
  86. fseek(file, 0, SEEK_SET);
  87.  
  88. return true;
  89. }
  90.  
  91. std::vector<std::string> TarFile::GetFileNames()
  92. {
  93. return file_names;
  94. }
  95.  
  96. bool TarFile::GetFileContents(const char* file_name, char* contents)
  97. {
  98. bool flag = false;
  99. for (int i = 0; i < file_names.size(); i++) {
  100. std::string name_(file_name);
  101.  
  102. if (file_names[i].compare(name_) == 0) {
  103. int file_size = file_sizes[i];
  104. flag = true;
  105. fseek(file, file_data_start_addrs[i], SEEK_SET);
  106. fread(contents, file_size, 1, file);
  107. fseek(file, 0, SEEK_SET);
  108.  
  109. break;
  110. }
  111. }
  112.  
  113. return flag;
  114. }
  115.  
  116. size_t TarFile::GetFileSize(const char* file_name)
  117. {
  118. size_t file_size{0};
  119.  
  120. for (int i = 0; i < file_names.size(); i++) {
  121. std::string name_(file_name);
  122.  
  123. if (file_names[i].compare(name_) == 0) {
  124. file_size = file_sizes[i];
  125. break;
  126. }
  127. }
  128.  
  129. return file_size;
  130. }
  131.  
  132. size_t TarFile::GetTarSize()
  133. {
  134. return size;
  135. }
  136.  
  137. //////////////////////////////////////////////
  138. int test_tar()
  139. {
  140. const std::string tar_file_path{ "E:/GitCode/Messy_Test/testdata/test.tar" };
  141. TarFile tarfile(tar_file_path.c_str());
  142.  
  143. bool is_valid_tar_file = tarfile.IsValidTarFile();
  144. if (!is_valid_tar_file) {
  145. fprintf(stderr, "it is not a valid tar file: %s\n", tar_file_path.c_str());
  146. return -1;
  147. }
  148.  
  149. fprintf(stderr, "tar file size: %d byte\n", tarfile.GetTarSize());
  150.  
  151. std::vector<std::string> file_names = tarfile.GetFileNames();
  152. fprintf(stderr, "tar file count: %d\n", file_names.size());
  153. for (auto name : file_names) {
  154. fprintf(stderr, "=====================================\n");
  155. size_t file_size = tarfile.GetFileSize(name.c_str());
  156. fprintf(stderr, "file name: %s, size: %d byte\n", name.c_str(), file_size);
  157.  
  158. char* contents = new char[file_size + 1];
  159. tarfile.GetFileContents(name.c_str(), contents);
  160. contents[file_size] = '\0';
  161.  
  162. fprintf(stderr, "contents:\n%s\n", contents);
  163. delete[] contents;
  164. }
  165.  
  166. return 0;
  167. }

测试结果如下:

GitHubhttps://github.com/fengbingchun/Messy_Test

C++实现tar包解析的更多相关文章

  1. Caffe实战三(依赖包解析及环境配置)

    前面的文章使用的软件环境是开始时通过apt-get命令所安装的,本文将通过编译源码的方式重新配置一个可迁移的软件环境.(参考:<深度学习 21天实战Caffe> 第五天 Caffe依赖包解 ...

  2. Linux RPM、TAR包管理

    一.RPM软件包命令的使用 RPM主要有5种基本操作模式:安装.卸载.刷新.升级及查询.下面分别介绍. 1.安装软件包 命令语法: rpm -ivh [RPM包文件名称] 命令中各参数的含义如下: - ...

  3. tar 只解压tar包中某个文件

    sh-4.1# ls test.tar sh-4.1# tar -tf test.tar ./ecs20161207.png ./ecs.png ./ecs.xml ./rds.png ./Scree ...

  4. find 查找文件 -exec 然后压缩 查看tar包的内容

    [root@cs Downloads]# find ./ -name "banner*" -exec tar -cvf k.tar "{}" \; ./bann ...

  5. java jar包解析:打包文件,引入文件

    java jar包解析:打包文件,引入文件 cmd下: jar命令:package包打包 javac命令:普通类文件打包 Hello.java: package org.lxh.demo; publi ...

  6. Unix系统解压tar包时出现@LongLink错误

    Unix系统上使用tar命令解压tar包后,多了一个@LongLink的文件,并且原来的tar包解压后不完整.网上查了下,原因是AIX系统上tar命令自身的一个缺陷.解决办法:把该tar包上传到lin ...

  7. Android做法说明(3)---Fragment使用app袋或v4包解析

    Android做法说明(3)---Fragment使用app袋或v4包解析 1)问题简述 相信非常多的朋友在调用Fragment都会遇到以下的情况: watermark/2/text/aHR0cDov ...

  8. linux tar包追加问题【转】

    只能已归档的文件才能追加文件. 如果tar.gz文件是如此生成:#tar -zcvf test.tar.gz  a.txt即tar.gz是压缩(-z)和归档(-c)文件,则无法给它追加文件:若果tar ...

  9. Spring (3.2.4) 常用jar 包解析

    Spring (3.2.4) 常用jar 包解析 基本jar包 spring-aop-3.2.4.RELEASE.jar spring-aspects-3.2.4.RELEASE.jar spring ...

随机推荐

  1. SQL SERVER中的And与Or的优先级

    数据库中有城市库表,其中有国家.省.城市. 举例:在广东省内(包含广东省本身),找出名称为“广州”的记录 首先,广东省内的条件是:ParentId = 2 Or Id =2 名称为“广州”的条件是:N ...

  2. Jquery Ajax 提交json数据

    在MVC控制器(这里是TestController)下有一个CreateOrder的Action方法 [HttpPost] public ActionResult CreateOrder(List&l ...

  3. linux下jira搭建&破解(转自:https://www.cnblogs.com/zpw-1/p/9553358.html)

    写在前面 网络类似文章不少,但是同样的路,别人走可能一马平川,自己走可能磕磕绊绊.记录一下自己搭建过程的一路踩坑历程[目前还记得的]. 一.环境准备 1,jira7.3的运行是依赖java环境的,也就 ...

  4. zabbix对网卡流量超出添加阈值

    给网卡设置流量阈值: 配置告警路径: Configuration--Templates--Template OS Linux--Discovery--Network interface discove ...

  5. HBase HA的分布式集群部署(适合3、5节点)

    本博文的主要内容有: .HBase的分布模式(3.5节点)安装    .HBase的分布模式(3.5节点)的启动 .HBase HA的分布式集群的安装 .HBase HA的分布式集群的启动    .H ...

  6. DotNET中的幕后英雄:MSCOREE.DLL

    现在做.NET Framework的开发的朋友应该是越来越多了,但是可能并非人人都对MSCOREE.DLL非常了解.而事实上,毫不夸张地说,MSCOREE.DLL是.NET Framework中最为核 ...

  7. NutzWk 5.0.x 微服务分布式版本开发及部署说明

    NutzWk 5.x 已发布一段时间,这段时间基于此版本开发了智慧水务系统(NB-IOT).某物联网平台.某设备租赁平台.某智慧睡眠平台.某智慧园区项目等,开发和部署过程中遇到一些小问题,开这个帖子把 ...

  8. 4-1 R语言函数 lapply

    #lapply函数 #可以循环处理列表中的每一个元素 #lapply(参数):lapply(列表,函数/函数名,其他参数) #总是返回一个列表 #sapply:简化结果 #结果列表元素长度均为1,返回 ...

  9. Smarty常用函数

    1 .include_once语句: 引用文件路径,路径必需正确.   eg:include_once("smarty/Smarty.class.php"); 2 $smarty= ...

  10. 判断浏览器是否为ie的最快方法

    var ie = !-[1,]; alert(ie); 只要6 bytes!它利用了IE与标准浏览器在处理数组的toString方法的差异做成的.对于标准游览器,如果数组里面最后一个字符为逗号,JS引 ...