文件打包
前言
在很多情况下,软件需要隐藏一些图片,防止用户对其更改,替换。例如腾讯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函数:
神奇的事情发生了,图片回来了
这只是一个小知识,用的也是熟悉的文件操作,打包的文件不包含文件夹,对于文件夹的打包方式,也是通过遍历文件夹下面的所有文件和文件夹,制作一张索引表,打包到一个文件里面。