??本文介紹基于C++ 語言,遍歷文件夾中的全部文件,并從中獲取指定類型的文件的方法。
??首先,我們來明確一下本文所需實(shí)現(xiàn)的需求?,F(xiàn)在有一個文件夾,其中包含了很多文件,如下圖所示;我們?nèi)绻氆@取其中所有類型為.bmp格式的文件的名稱,如果文件數(shù)量比較多的話,手動篩選就會很麻煩。而借助C++ 代碼就可以簡單地實(shí)現(xiàn)這一需求。如果需要借助Python代碼來實(shí)現(xiàn)同樣的需求,可以參考文章Python中ArcPy批量掩膜、批量重采樣?xùn)鸥襁b感影像(http://www.itdecent.cn/p/c71e470916bb),基于其中提到的arcpy.ListRasters()函數(shù)來實(shí)現(xiàn)。

??首先需要說明的是,本文代碼只能實(shí)現(xiàn)對某一文件夾下的文件進(jìn)行遍歷并篩選;如果是當(dāng)前文件夾下的子文件夾中的文件,這一代碼是沒有辦法遍歷的。大家如果有相關(guān)需求的話,可以嘗試在本文代碼中加幾個判斷語句來實(shí)現(xiàn);或者參考基于ArcPy將HDF格式柵格文件批量轉(zhuǎn)為TIFF格式(http://www.itdecent.cn/p/219d0ab1a60f)、Python統(tǒng)計文件夾所含文件數(shù)量與其子文件夾中文件總數(shù)量(http://www.itdecent.cn/p/1d739431cc52)這兩篇文章,基于其中提到的方法用Python代碼來實(shí)現(xiàn)。
??本文分為兩部分,第一部分為代碼的分段講解,第二部分為完整代碼。
1 分段代碼介紹
1.1 代碼準(zhǔn)備
??這一部分主要是代碼的頭文件、命名空間與我們自行撰寫的自定義函數(shù)get_need_file()的聲明;具體代碼如下所示。
#include <iostream>
#include <vector>
#include <io.h>
using namespace std;
void get_need_file(string path, vector<string>& file, string ext);
??其中,由于我們在接下來的代碼中需要用到容器vector這一數(shù)據(jù)類型,因此首先需要添加#include <vector>;同時,我們在接下來的代碼中需要用到頭文件io.h中的部分函數(shù)(主要都是一些與計算機(jī)系統(tǒng)、文件管理相關(guān)的函數(shù)),因此需要添加#include <io.h>。
??接下來,這里聲明了一個自定義函數(shù)get_need_file(),具體我們在本文1.3部分介紹。
1.2 主函數(shù)
??這一部分介紹代碼的main()函數(shù);具體代碼如下所示。
int main() {
string file_path = R"(E:\02_Project\02_ChlorophyllProduce\01_Data\00_Test)";
vector<string> my_file;
string need_extension = ".bmp";
get_need_file(file_path, my_file, need_extension);
for (int i = 0; i < my_file.size(); i++)
{
cout << "File " << i+1 << " is:" << endl;
cout << my_file[i] << endl;
}
if (my_file.size() == 0)
{
cout << "No file can be found!" << endl;
}
else
{
cout << endl << "Find " << my_file.size() << " file(s)." << endl;
}
return 0;
}
??首先,我們定義了幾個后續(xù)代碼需要用到的變量。其中,file_path是一個字符串string變量,表示我們需要進(jìn)行文件遍歷的文件夾路徑;這里我們用R"()"取消其中路徑轉(zhuǎn)義字符的使用。my_file是一個容器vector變量,其中將會存儲我們需要篩選出來的特定文件。need_extension是我們需要篩選出來的特定文件的格式后綴。這些變量是如何工作的,具體我們在本文1.3部分介紹。
??隨后,調(diào)用自定義函數(shù)get_need_file();調(diào)用完畢后,my_file中就存儲了我們需要篩選出來的特定文件(如果有的話)。
??最后,for循環(huán)來輸出我們找到的文件名稱;if判斷則是輸出我們最終有沒有篩選出指定格式的文件,如果篩選出來的話則會輸出具體篩選出的文件數(shù)量。
??主函數(shù)部分整體比較簡單,這里就不再贅述。
1.3 自定義函數(shù)
??這一部分介紹代碼的自定義函數(shù)get_need_file(),也是本文最重要的部分;具體代碼如下所示。
void get_need_file(string path, vector<string>& file, string ext)
{
intptr_t file_handle = 0;
struct _finddata_t file_info;
string temp;
if ((file_handle = _findfirst(temp.assign(path).append("/*" + ext).c_str(), &file_info)) != -1)
{
do
{
file.push_back(temp.assign(path).append("/").append(file_info.name));
} while (_findnext(file_handle, &file_info) == 0);
_findclose(file_handle);
}
}
??其中,自定義函數(shù)get_need_file()的三個參數(shù),依次就是我們在主函數(shù)中定義的三個變量。
??在自定義函數(shù)get_need_file()中,我們首先定義了intptr_t類型的變量file_handle,并對其賦值為0。首先,這里的intptr_t是一種與計算機(jī)系統(tǒng)有關(guān)的數(shù)據(jù)類型,專門用來存放指針的地址;相較于用標(biāo)準(zhǔn)的int格式、long格式存儲指針的地址,其具有更高的安全性,因此在計算機(jī)系統(tǒng)中通常用其存儲指針的地址。其次,這里的file_handle表示文件句柄;在計算機(jī)系統(tǒng)中,每一個文件都有一個唯一的編號(相當(dāng)于我們每一個人都有一個唯一的身份證號碼),不同的文件具有不同的句柄,依據(jù)這一個句柄計算機(jī)系統(tǒng)就能鎖定其對應(yīng)的那個唯一的文件。因為文件句柄就是一個指向指針的指針,亦即指針的地址,因此我們就將其設(shè)定為intptr_t類型。此外,為其賦值為0,就是相當(dāng)于先暫時隨便給它賦一個肯定不對的數(shù)值,之后程序會自動替換。
??接下來,我們定義一個_finddata_t類型的變量file_info。首先,這里的_finddata_t其實(shí)是一個結(jié)構(gòu)體,專門用來存儲計算機(jī)系統(tǒng)中不同文件的各類信息;而file_info就是文件的不同信息。前面我們提到,file_handle相當(dāng)于我們的身份證號碼,那么這里file_info相當(dāng)于就是存儲了我們性別、家庭住址、愛好等信息的個人信息庫。
??隨后,我們再定義一個字符串string類型的變量temp,其用來存儲臨時生成的文件路徑。
??接下來,進(jìn)入if判斷語句;這里我們將其拆開來看。首先,temp.assign(path).append("/*" + ext)其實(shí)就表示我們需要篩選的特定格式的文件,在本文中即E:\02_Project\02_ChlorophyllProduce\01_Data\00_Test)/*.bmp,并將其通過.assign()函數(shù)賦給字符串temp。隨后,.c_str()函數(shù)將前面賦值好的字符串temp轉(zhuǎn)為標(biāo)準(zhǔn)的C語言的格式(這是因為后面操作需要保證字符串為標(biāo)準(zhǔn)的C語言格式)。隨后,將轉(zhuǎn)換好的C語言格式字符串作為第一個參數(shù),帶入_findfirst()函數(shù);其第二個參數(shù)則是file_info。_findfirst()函數(shù)的功能是在當(dāng)前路徑下,找到與第一個參數(shù)(在這里也就是轉(zhuǎn)換好的C語言格式字符串)相匹配的第一個文件;如果能找到這個文件,那么其就返回該文件的句柄,并將該文件的信息放入file_info;如果找不到這個文件,那么該函數(shù)就返回-1。因此,這里的if判斷語句表示,一旦在當(dāng)前路徑下找到我們需要的文件,就繼續(xù)進(jìn)行接下來的代碼;如果找不到需要的文件,那么相當(dāng)于當(dāng)前文件夾下就沒有符合我們要求的文件。
??接下來,執(zhí)行do語句內(nèi)部的代碼。其中,temp.assign(path).append("/").append(file_info.name)就表示當(dāng)前找到的文件的路徑及其名稱,并通過push_back()函數(shù)將其附加至vector變量file的末尾。隨后,進(jìn)行while語句內(nèi)部代碼的判斷——其中,_findnext()函數(shù)其實(shí)和前面的_findfirst()函數(shù)比較類似,它的作用是按照當(dāng)前_findfirst()函數(shù)中所指定的文件篩選要求,進(jìn)行繼續(xù)篩選(_findfirst()函數(shù)相當(dāng)于是找到了第一個符合我們篩選要求的文件,而_findnext()函數(shù)就是繼續(xù)找,找到下一個符合要求的文件);如果其找到了,那么就將所找到的文件的句柄與信息返回到其兩個參數(shù)中,且返回一個值0;如果沒有找到的話就返回-1。因此,這里while語句相當(dāng)于就是判斷當(dāng)前路徑下還有沒有我們需要的文件,如果有的話就再執(zhí)行do語句內(nèi)部的代碼(即將文件的路徑放入vector變量file的末尾);如果沒有的話,那么就結(jié)束前面的循環(huán)。
??最后,_findclose()表示將當(dāng)前句柄所表示的文件加以關(guān)閉,并將對應(yīng)的文件資源釋放。
2 完整代碼
??本文所用到的全部代碼如下。
#include <iostream>
#include <vector>
#include <io.h>
using namespace std;
void get_need_file(string path, vector<string>& file, string ext);
int main() {
string file_path = R"(E:\02_Project\02_ChlorophyllProduce\01_Data\00_Test)";
vector<string> my_file;
string need_extension = ".bmp";
get_need_file(file_path, my_file, need_extension);
for (int i = 0; i < my_file.size(); i++)
{
cout << "File " << i + 1 << " is:" << endl;
cout << my_file[i] << endl;
}
if (my_file.size() == 0)
{
cout << "No file can be found!" << endl;
}
else
{
cout << endl << "Find " << my_file.size() << " file(s)." << endl;
}
return 0;
}
void get_need_file(string path, vector<string>& file, string ext)
{
intptr_t file_handle = 0;
struct _finddata_t file_info;
string temp;
if ((file_handle = _findfirst(temp.assign(path).append("/*" + ext).c_str(), &file_info)) != -1)
{
do
{
file.push_back(temp.assign(path).append("/").append(file_info.name));
} while (_findnext(file_handle, &file_info) == 0);
_findclose(file_handle);
}
}
??運(yùn)行上述代碼后,將會得到所篩選出的文件各自的名稱,以及其具體數(shù)量。

??至此,大功告成。