现在咱们说说解包,一个.dat文件,里面不知道包含了多少个文件/文件夹的信息,我们怎么解包呢?又怎么保证文件与文件之间、文件与其子文件之间的分级对应关系呢?下面我们来回顾一下打包的过程:把文件/文件夹的外部信息(文件名、文件名长度、文件的长度)/(文件夹名、文件夹名长度、文件的长度、文件的相对路径信息、文件类型)以结构体的形式存放在.dat文件中,内容也保存到.dat文件中
解包参数设置: bool UnPackFileAndDirectory(const string& inputzipfile, const string& outputpath)
其中第一个参数inputzipfile是要解包哪个文件(全路径),第二个参数outputpath是解包在哪一路径下(给定路径)
解包按照打包接口逻辑的话:文件、文件夹的顺序读取内容即可,当然啦,两边的结构体信息要定义相同,这样大家的协议就一样,解包便不会出现问题了。
解包流程:1.定位解包文件;2.解包文件部分(文件外部信息+文件内容),写入到指定路径下;3.解包文件夹部分(文件夹外部信息,没有内容哈,文件夹的内容为0),创建文件夹,并建立在指定路径下
1 bool UnPackFileAndDirectory(const string& inputzipfile, const string& outputpath) 2 { 3 FILE *rfp = NULL; 4 rfp = fopen(inputzipfile.c_str(), "rb"); 5 if (rfp == NULL) 6 { 7 cout << "解包:文件打开失败!" << endl; 8 return false; 9 } 10 11 //文件部分 12 int filecount; 13 fread(&filecount, sizeof(filecount), 1, rfp); 14 15 for (size_t i = 0; i < filecount; i++) 16 { 17 struct FileInfo packFile; 18 fread(&packFile, sizeof(packFile), 1, rfp); 19 20 cout << "filename:" << packFile.FileName << ", nameLen:" << packFile.fileNameLen << ", fileLen:" << packFile.fileSize << endl; 21 string path_file = outputpath + '\\' + packFile.FileName; //path_file:全路径 22 23 FILE *unpackFile = NULL; 24 unpackFile = fopen(path_file.c_str(), "wb"); 25 if (unpackFile == NULL) 26 { 27 cout << "文件:文件创建失败!" << endl; 28 } 29 30 unsigned char*tmpBu = new unsigned char[packFile.fileSize]; 31 fread(tmpBu, packFile.fileSize, 1, rfp);//当然也可以不借助缓冲区 32 fwrite(tmpBu, packFile.fileSize, 1, unpackFile); 33 34 } 35 cout << endl; 36 37 //文件夹部分 38 int folderCount; 39 fread(&folderCount, sizeof(folderCount), 1, rfp); 40 41 for (size_t i = 0; i < folderCount; i++) 42 { 43 struct FolderInfo folder; 44 fread(&folder, sizeof(folder), 1, rfp); 45 46 //文件夹的基本信息 47 cout << "FolderName:" << folder.FolderName << ", nameLen:" << folder.FolderNameLen << ", FolderSize:" << folder.FileSize << ", path:" << folder.Filepath << ", type:" << folder.type << endl; 48 49 string path_folder = outputpath + '\\' + folder.Filepath; //解包后全路径 50 const char * Lpath = path_folder.c_str(); 51 52 if (folder.type == 0 ) //文件类型 53 { 54 FILE * unpackFolders = NULL; 55 unpackFolders = fopen(path_folder.c_str(), "wb"); 56 if (unpackFolders == NULL) 57 { 58 cout << "文件夹:子文件创建失败!" << endl; 59 } 60 61 unsigned char*readFolder = new unsigned char[folder.FileSize]; 62 fread(readFolder, folder.FileSize, 1, rfp); 63 fwrite(readFolder, folder.FileSize, 1, unpackFolders); 64 65 } 66 if (folder.type == 1)//文件夹类型 67 { 68 ::CreateDirectory(Lpath, NULL); //创建文件夹 69 } 70 } 71 72 return true; 73 }
细心的小伙伴都发现了,我在文件解包和打包的过程中,都用到了临时的缓冲区:unsigned char*tmpBu = new unsigned char[fileSize];我为什么不直接从一个文件读再写入目标文件呢?主要是我之前就是那么干的,结果发现有的文件解包出来与原来的文件并不一致。我用的对比软件是BeyongCompare 4,这个软件是我直属领导安利的,可以对比两个文件/文件夹是否一样,而且任何格式的都可以,这样的软件对我来说简直就是黑科技,amazing~
我想请教各位C++大神,如何不借助缓冲区,实现咱们这个功能呢?
-------------------------------------------------------------(分割线)------------------------------------------------------------------------------------------------------
之前有位大神在我博文下评论,说我new的空间没有释放(造成内存泄漏),get到了,大家不要跟我一样粗心哦~
文件打包解包这一专题终于写完了,好开心呀。有需要改进完善的地方欢迎大家提出宝贵意见,膜拜各位大佬 ...