本文介绍基于
C++
语言,遍历文件夹中的全部文件,并从中获取
指定类型
的文件的方法。

首先,我们来明确一下本文所需实现的需求。现在有一个文件夹,其中包含了很多文件,如下图所示;我们如果想获取其中所有类型为
.bmp
格式的文件的名称,如果文件数量比较多的话,手动筛选就会很麻烦。而借助
C++
代码就可以简单地实现这一需求。如果需要借助
Python
代码来实现同样的需求,可以参考文章
Python ArcPy批量掩膜、重采样大量遥感影像
,基于其中提到的
arcpy.ListRasters()
函数来实现。

首先需要说明的是,本文代码只能实现对
某一文件夹下的文件
进行遍历并筛选;如果是当前文件夹下的
子文件夹中
的文件,这一代码是没有办法遍历的。大家如果有相关需求的话,可以尝试在本文代码中加几个判断语句来实现;或者参考
HDF格式遥感影像批量转为TIFF格式:ArcPy实现

Python求取文件夹内的文件数量、子文件夹内的文件数量
这两篇文章,基于其中提到的方法用
Python
代码来实现。

本文分为两部分,第一部分为代码的分段讲解,第二部分为完整代码。

1 分段代码介绍

1.1 代码准备

这一部分主要是代码的头文件、命名空间与我们
自行撰写的自定义函数
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
这一数据类型,因此首先需要添加
#include <vector>
;同时,我们在接下来的代码中需要用到头文件
io.h
中的部分函数(主要都是一些与计算机系统、文件管理相关的函数),因此需要添加
#include <io.h>

接下来,这里声明了一个自定义函数
get_need_file()
,具体我们在本文
1.3
部分介绍。

1.2 主函数

这一部分介绍代码的
main()
函数;具体代码如下所示。

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;
}

首先,我们定义了几个后续代码需要用到的变量。其中,
file_path
是一个字符串
string
变量,表示我们需要进行文件遍历的文件夹路径;这里我们用
R"()"
取消其中路径转义字符的使用。
my_file
是一个容器
vector
变量,其中将会存储我们需要筛选出来的特定文件。
need_extension
是我们需要筛选出来的特定文件的格式后缀。这些变量是如何工作的,具体我们在本文
1.3
部分介绍。

随后,调用自定义函数
get_need_file()
;调用完毕后,
my_file
中就存储了我们需要筛选出来的特定文件(如果有的话)。

最后,
for
循环来输出我们找到的文件名称;
if
判断则是输出我们最终有没有筛选出指定格式的文件,如果筛选出来的话则会输出具体筛选出的文件数量。

主函数部分整体比较简单,这里就不再赘述。

1.3 自定义函数

这一部分介绍代码的自定义函数
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);
	}
}

其中,自定义函数
get_need_file()
的三个参数,依次就是我们在主函数中定义的三个变量。

在自定义函数
get_need_file()
中,我们首先定义了
intptr_t
类型的变量
file_handle
,并对其赋值为
0
。首先,这里的
intptr_t
是一种与计算机系统有关的数据类型,专门用来存放
指针的地址
;相较于用标准的
int
格式、
long
格式存储
指针的地址
,其具有更高的安全性,因此在计算机系统中通常用其存储
指针的地址
。其次,这里的
file_handle
表示文件句柄;在计算机系统中,每一个文件都有一个唯一的编号(相当于我们每一个人都有一个唯一的身份证号码),不同的文件具有不同的句柄,依据这一个句柄计算机系统就能锁定其对应的那个唯一的文件。因为文件句柄就是一个
指向指针的指针
,亦即
指针的地址
,因此我们就将其设定为
intptr_t
类型。此外,为其赋值为
0
,就是相当于先暂时随便给它赋一个肯定不对的数值,之后程序会自动替换。

接下来,我们定义一个
_finddata_t
类型的变量
file_info
。首先,这里的
_finddata_t
其实是一个结构体,专门用来存储计算机系统中不同文件的各类信息;而
file_info
就是文件的不同信息。前面我们提到,
file_handle
相当于我们的身份证号码,那么这里
file_info
相当于就是存储了我们性别、家庭住址、爱好等信息的个人信息库。

随后,我们再定义一个字符串
string
类型的变量
temp
,其用来存储临时生成的文件路径。

接下来,进入
if
判断语句;这里我们将其拆开来看。首先,
temp.assign(path).append("/*" + ext)
其实就表示我们需要筛选的特定格式的文件,在本文中即
E:\02_Project\02_ChlorophyllProduce\01_Data\00_Test)/*.bmp
,并将其通过
.assign()
函数赋给字符串
temp
。随后,
.c_str()
函数将前面赋值好的字符串
temp
转为标准的
C
语言的格式(这是因为后面操作需要保证字符串为标准的
C
语言格式)。随后,将转换好的
C
语言格式字符串作为第一个参数,带入
_findfirst()
函数;其第二个参数则是
file_info

_findfirst()
函数的功能是在当前路径下,找到与第一个参数(在这里也就是转换好的
C
语言格式字符串)相匹配的第一个文件;如果能找到这个文件,那么其就返回该文件的句柄,并将该文件的信息放入
file_info
;如果找不到这个文件,那么该函数就返回
-1
。因此,这里的
if
判断语句表示,一旦在当前路径下找到我们需要的文件,就继续进行接下来的代码;如果找不到需要的文件,那么相当于当前文件夹下就没有符合我们要求的文件。

接下来,执行
do
语句内部的代码。其中,
temp.assign(path).append("/").append(file_info.name)
就表示当前找到的文件的路径及其名称,并通过
push_back()
函数将其附加至
vector
变量
file
的末尾。随后,进行
while
语句内部代码的判断——其中,
_findnext()
函数其实和前面的
_findfirst()
函数比较类似,它的作用是按照当前
_findfirst()
函数中所指定的文件筛选要求,进行继续筛选(
_findfirst()
函数相当于是找到了第一个符合我们筛选要求的文件,而
_findnext()
函数就是继续找,找到下一个符合要求的文件);如果其找到了,那么就将所找到的文件的句柄与信息返回到其两个参数中,且返回一个值
0
;如果没有找到的话就返回
-1
。因此,这里
while
语句相当于就是判断当前路径下还有没有我们需要的文件,如果有的话就再执行
do
语句内部的代码(即将文件的路径放入
vector
变量
file
的末尾);如果没有的话,那么就结束前面的循环。

最后,
_findclose()
表示将当前句柄所表示的文件加以关闭,并将对应的文件资源释放。

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);
	}
}

运行上述代码后,将会得到所筛选出的文件各自的名称,以及其具体数量。

至此,大功告成。

标签: none

添加新评论