文件(含多級子目錄)的打包和解包(上)


  在公司做項目的時候,有打包和解包文件的需求,而文件為任意類型(eg:txt、exe、dll、jpg、osg、bmp、avi...),剛遇到這個問題,滿腦子都是這么多格式的文件僅用打包和解包兩個接口如何實現呢,簡直難死了,又不能不實現這個功能,就喝了兩袋咖啡,冷靜半個鍾頭,決定好好研究一番。

  先從文件這個概念入手,相信軟件研發的人員都不陌生,計算機存儲都是以文件的形式,對文件的操作分為三步:打開文件-讀寫-關閉文件(與把大象放在冰箱里是一個流程,哈哈),看起來簡簡單單的三步,卻花費了我兩周的時間。

  先說說打包吧,就是把所有的文件打包在一個.dat文件中(二進制的,至於什么名字嘛,你開心就好,無所謂啦),要打包的文件,實則分為兩部分:文件和文件夾,所以打包的接口我就寫的麻煩了些,把文件和文件夾分開:

bool PackFileAndDirectory(const std::vector<std::string>& files, const std::vector<std::string>& directories, const std::string& outputfilename);

參數說明: files: 文件(全路徑)、directories: 文件夾(全路徑)、outputfilename: 打包后輸出的文件名(全路徑)、返回值: 成功返回true,失敗返回false  

  解包的接口設計,即:有一個打包好的文件,你把它解包成多個文件,並且文件的級別信息不能出錯,內容也不能張冠李戴(類似於咱們用windows的一鍵解包)

bool UnPackFileAndDirectory(const std::string& inputzipfile, const std::string& outputpath);解包文件和文件夾到某一個目錄下

參數說明:inputzipfile: 待解包的文件(全路徑)、outputpath: 輸出到的目標位置,將解包后的所有文件和文件夾放到該文件夾下(全路徑)、返回值: 成功返回true,失敗返回false

  先針對打包接口:

  第一個參數:文件,這個比較簡單,就是把所有文件的全路徑放在vector中,能利用全路徑獲取到文件的基本信息:文件名、文件內容等等。

  第二個參數:文件夾,這個就會麻煩些,因為存在多個文件夾,每個文件夾又可能是包含多級子目錄,先拿一個文件夾來說吧,首先我們必須獲取這個文件夾的信息:文件夾的名字、名字長度、路徑等等,還要設計一個遍歷文件夾所有子目錄的函數,保留級別的對應關系,在路徑這一塊,我想了很久,不能用全路徑(為啥呢->假如全路徑,那等解包的時候,別人讓你解包在哪個盤就哪個盤,你總不能帶着自己原先所在盤的路徑吧 (eg:把C:/test/file1.txt打包好了,解包需求是解在:D:/tmp/unpack/下,你發現自己的打包文件中存的路徑信息是:C:/test/file1.txt,解包后就會出現D:/tmp/unpack/C:/test/file1.txt,這樣怎么可能生成一個文件呢),所以我采用了一種相對路徑法:解包路徑+自己的相對路徑,完美的解決了路徑問題

  文件:統計文件個數、獲取文件信息、獲取文件內容; 文件夾:從保留多級目錄關系的思路中跳出來,保留路徑信息(不是原路徑信息,而是解包后的全路徑信息),文件夾內容為0,文件的內容進行獲取,遍歷所有子級+父級的文件個數、文件信息等等

  遍歷一個文件夾的所有子目錄:

 1 void GetAllSubFiles(string path, vector<string>& files)//獲取所有的子文件
 2 {
 3     long hFile = 0;
 4     struct _finddata_t fileinfo;
 5     string p;
 6     if ((hFile = _findfirst(p.assign(path).append("\\*").c_str(), &fileinfo)) != -1)
 7     {
 8         do
 9         {
10             if ((fileinfo.attrib &  _A_SUBDIR))
11             {
12                 if (strcmp(fileinfo.name, ".") != 0 && strcmp(fileinfo.name, "..") != 0)
13                 {
14                     files.push_back(p.assign(path).append("\\").append(fileinfo.name));
15                     GetAllSubFiles(p.assign(path).append("\\").append(fileinfo.name), files);
16                 }
17             }
18             else
19             {
20                 files.push_back(p.assign(path).append("\\").append(fileinfo.name));
21             }
22 
23         } while (_findnext(hFile, &fileinfo) == 0);
24 
25         _findclose(hFile);
26     }
27 }

 

  打包文件部分:

 1 bool PackFileAndDirectory(const vector<string>& files, const vector<string>& directories, const string& outputfilename) //打包:寫文件的過程
 2 {
 3     FILE *wfp = NULL;  
 4     wfp = fopen(outputfilename.c_str(), "wb");
 5     if (wfp == NULL)
 6     {
 7         cout << "打包:文件打開失敗!" << endl;
 8     }
 9 
10     /************************第一個參數:文件vector**********************/
11 
12     int fileCount = files.size();
13     fwrite(&fileCount, sizeof(fileCount), 1, wfp);
14 
15     for (size_t i = 0; i < fileCount; i++)
16     {
17         struct FileInfo file;
18 
19         string path = files[i]; //雙斜杠路徑名
20         string filename = getFileNameFromPath(path);//根據路徑獲取文件名
21         strcpy(file.FileName, filename.c_str());
22         file.fileNameLen = strlen(filename.c_str());
23 
24         ifstream fin;
25         fin.open(path, ios::binary);
26 
27         fin.seekg(0, ios::end);
28         streampos sp = fin.tellg();
29         file.fileSize = sp; //文件的size
30 
31         fwrite(&file, sizeof(file), 1, wfp);
32         cout << "filename:" << file.FileName << ";  filenameLength:" << file.fileNameLen << ";  fileSize:" << file.fileSize << endl;
33 
34         FILE *files = fopen(path.c_str(), "rb");
35         eachFile = new unsigned char[file.fileSize];
36         fileBuffer.push_back(eachFile);
37         fread(fileBuffer[i], file.fileSize, 1, files);
38 
39         fwrite(fileBuffer[i], file.fileSize, 1, wfp);
40     }
41 }

 

  今天先說這么多,打包里面有很多細小的知識點,真正去做才會發現,所以必須鞏固自己的基礎,作為一名職場小白+程序媛,文中假如有需要改進的觀點和看法,還望各位IT界的大神賜教,O(∩_∩)O~

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM