专栏首页编程学习基地文件打包解包的方法

文件打包解包的方法

文件打包

前言

在很多情况下,软件需要隐藏一些图片,防止用户对其更改,替换。例如腾讯QQ里面的资源图片,哪怕你用Everything去搜索也搜索不到,那是因为腾讯QQ对这些资源图片进行了打包,当软件运行的时候解包获取资源图片。

举个栗子:

这是我用RDB打包解包工具对QQ某一目录下的.rdb文件进行解包得到的表情包资源,还有头像资源等等。。

这种打包不是压缩包那种经过算法压缩,而是将一堆资源写入到一个文件里面,解包的时候按照打包的方式读取,达到防止用户出于恶趣味更改图片资源。

就好比你在清理内存的时候删除了一些较大的文件,恰巧这个文件就是某游戏的地图资源,导致某游戏地图变成黑色区域。所以就有建议不要乱删电脑里面的任何不确定的文件。

这期介绍下C++利用文件操作进行文件的打包解包..

正文

打包解包


要想将文件打包生成文件,我们需要一张索引表,索引表里面包括关于文件的信息,例如文件名,文件大小..

索引表之后就是文件内容,假设我有四张图片,需要将四张图片打包生成一个.pack包,并且pack包能够被解开获取里面的内容

首先看一下索引表有什么内容

首先是红色区域,占8个字节,存储索引表的信息,索引表的左边是索引表的大小,右边是文件数量

其次是索引表中包含的文件信息,从左到右依次是文件名大小、文件偏移量,文件大小,文件名

文件偏移量:就是资源文件在打包文件中的位置

然后开始关于C++文件操作的打包解包:

#include<iostream>
using namespace std;
#include <fstream>
//索引表大小:4  文件数量:4   文件1大小 文件1偏移  文件1名大小 文件1名  文件2.。。
struct FileInfo
{
  int fileNameSize;  //文件名字大小
  int fileOffset;    //文件的偏移量
  int fileSize;    //文件的大小
  char fileName[20];  //文件名
};
void packFile()
{
  FileInfo fileList[4] = {
    { 0,0,0,"1.jpg" },
    { 0,0,0,"2.jpg" },
    { 0,0,0,"3.jpg" },
    { 0,0,0,"4.jpg" }
  };
  fstream file[4];

  int listSize = 0;  //索引表大小
  int fileNum = 4;  //文件数量
  for (int i = 0; i < 4; i++)
  {
    fileList[i].fileNameSize = strlen(fileList[i].fileName) + 1;  //1是\0
    listSize += fileList[i].fileNameSize + 12;  //求索引表的大小

    file[i].open(fileList[i].fileName, ios_base::in | ios_base::binary);  //打开文件
    file[i].seekp(0, ios_base::end);          //读指针移动到末尾
    fileList[i].fileSize = file[i].tellp();        //获取文件大小
    file[i].seekp(0, ios_base::beg);          //读指针移动到开头
  }
  //写文件索引信息
  fstream outfile("new.pack", ios_base::out | ios_base::binary);
  outfile.write((char*)&listSize, 4);
  outfile.write((char*)&fileNum, 4);
  //写索引表
  for (int i = 0; i < 4; i++)
  {
    if (i == 0)
      fileList[i].fileOffset = 8 + listSize;
    else
      fileList[i].fileOffset = fileList[i - 1].fileOffset + fileList[i - 1].fileSize;

    outfile.write((char*)&fileList[i].fileNameSize, 4);
    outfile.write((char*)&fileList[i].fileOffset, 4);
    outfile.write((char*)&fileList[i].fileSize, 4);
    outfile.write((char*)&fileList[i].fileName, fileList[i].fileNameSize);
  }
  //写文件
  char ch;
  for (int i = 0; i < 4; i++)
  {
    while (ch = file[i].get(),!file[i].eof())
    {
      outfile.put(ch);
    }
    file[i].close();
  }
  outfile.close();
}
void unPackFile() 
{
  fstream inFile;
  inFile.open("new.pack", ios_base::in | ios_base::binary);
  int listSize;  //索引表大小
  int fileNum;  //文件数量
  //读文件索引信息
  inFile.read((char*)&listSize, 4);
  inFile.read((char*)&fileNum, 4);

  FileInfo* fileList = new FileInfo[fileNum];
  fstream *file = new fstream[fileNum];
  //读索引表
  for (int i = 0; i < fileNum; i++)
  {
    inFile.read((char*)&fileList[i].fileNameSize, 4);
    inFile.read((char*)&fileList[i].fileOffset, 4);
    inFile.read((char*)&fileList[i].fileSize, 4);
    inFile.read((char*)&fileList[i].fileName, fileList[i].fileNameSize);
    file[i].open(fileList[i].fileName, ios_base::out|ios_base::binary);
  }
  
  for (int i = 0; i < fileNum; i++)
  {
    for (int j = 0; j < fileList[i].fileSize; j++)
    {
      file[i].put(inFile.get());
    }
    file[i].close();
  }
  inFile.close();
  delete[] fileList;
  delete[] file;
}
int main()
{
  packFile();
  //unPackFile();
  return 0;
}

工作目录下准备4张用于打包的图片:

运行程序,得到new.pack文件:

删除掉4张jpg图片,只留下new.pack文件:

调用upPackFile函数:

神奇的事情发生了,图片回来了

这只是一个小知识,用的也是熟悉的文件操作,打包的文件不包含文件夹,对于文件夹的打包方式,也是通过遍历文件夹下面的所有文件和文件夹,制作一张索引表,打包到一个文件里面。

本文分享自微信公众号 - 编程学习基地(LearnBase),作者:DeRoy

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2020-05-11

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Git使用指南

    所有的版本控制系统,只能跟踪文本文件的改动,比如txt文件,网页,所有程序的代码等,但是图片,视频这些二进制文件,虽能也能由版本控制系统管理,但没法跟踪文件的变...

    DeROy
  • C到C++II

    结构,联合,枚举C++结构体C++联合C++枚举bool类型内联重载缺省参数和哑元哑元引用引用特点引用做参数引用做函数返回值

    DeROy
  • ubantu16.04搭建Qt环境

    「下载 qt-everywhere-opensource-src-4.8.7.tar.gz:http://download.qt-project.org/arc...

    DeROy
  • Python教学——第七天

    如果你前面都跟着文章做了,相信你已经自己在私下也了解了很多知识 如果你之前全都没有跟着做,也没有关系,至少你可以了解一个概念,对将来动手的时候会有一定的帮助 如...

    企鹅号小编
  • SpringBoot启动banner更改

    dalaoyang
  • Mac OS如何恢复出厂设置?安装Mac OS系统教程

    Mac怎么恢复出厂设置?苹果Mac电脑系统一直以稳定安全著称,但有时候Mac OS也会由于某些原因出现运行缓慢、系统崩溃或无法正常启动等的情况,这时候就需要我们...

    MAC先森
  • 贪心凑面值

    无道
  • 网站SEO关键词布局核心优化策略

    随着互联网的高速发展,越来越多的企业认识到了SEO优化对于品牌推广的重要性,作为一名合格的SEO站长,网站关键词排名上升是我们坚持不懈的驱动力。虽然说现在找一个...

    阿南SEO
  • AngularJS API之isXXX()

    Angular中保存了很多的判断方法,可以用来验证对象是否符合某种要求,详细的参考代码样例即可 <html> <head> <meta http-...

    用户1154259
  • kubernetes v1.11 二进制部署(二)之Openssl自签TLS证书

    节点kubelet的公钥与私钥:是通过boostrap响应的方式,在启动kubelet自动会产生, 然后在master通过csr请求,就会产生。 那么知道这些...

    Devops海洋的渔夫

扫码关注云+社区

领取腾讯云代金券