C/C++获取当前目录,文件列表,遍历文件夹和文件

C++17之后支持了std::filesystem模块,可以很方便的操作文件系统,这里仅针对C++17版本以下的程序提供便捷的代码样例便于直接使用,支持windows和linux双平台。

常用代码片段

#include <iostream>
#include <string>
#include <vector>

#if _WIN32
	#include <direct.h>
	#include <objbase.h>
	#include <io.h>
#else
	#include <unistd.h>
	#include <sys/stat.h>
	#include <dirent.h>
#endif

std::string GetCurrentPath()
{
	char path[512] = { 0 };
#if _WIN32
	_getcwd(path, sizeof(path));
#else
	getcwd(path, sizeof(path));
#endif

	return path;
}


bool CreateFolder(const std::string& path)
{
	// FIXME: only support one level folder not recursively
	// if the direcotry already exist, will not create
	int ret;
#ifdef WIN32
	ret = _mkdir(path.c_str());
#else
	ret = mkdir(path.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
#endif

	return ret == 0;
}

std::vector<std::string> GetFilenameList(const std::string& dir)
{
	// FIXME: dir should be absolute path folder in windows, linux support relative path
	// should has no suffix "/"
	std::vector<std::string> filename_list;

#ifdef _WIN32

	_finddata_t file_info;
	std::string current_path = dir + "/*.*";

	intptr_t handle = _findfirst(current_path.c_str(), &file_info);

	if (handle != -1)
	{
		do
		{
			if (file_info.attrib != _A_SUBDIR
				&& std::string(file_info.name) != "."
				&& std::string(file_info.name) != "..")
				filename_list.push_back(file_info.name);
		} while (!_findnext(handle, &file_info));
	}
	_findclose(handle);
#else
	DIR* pDir;
	struct dirent* ptr;
	if (pDir = opendir(dir.c_str()))
	{
		while ((ptr = readdir(pDir)) != 0)
		{
			if (ptr->d_type != DT_DIR
				&& strcmp(ptr->d_name, ".") != 0
				&& strcmp(ptr->d_name, "..") != 0)
			{
				filename_list.push_back(ptr->d_name);
			}
		}
	}
	closedir(pDir);
#endif

	return filename_list;
}

int main()
{
	std::string pwd_path = GetCurrentPath();
	CreateFolder("./mydir");
	auto filenames = GetFilenameList("C:");

    return 0;
}

递归遍历文件夹和文件

以下仅以windows上面为例

库函数

包含头文件 #include <io.h>

用到数据结构_finddata_t,文件信息结构体的指针。

struct _finddata_t
{
    unsigned attrib;     //文件属性
    time_t time_create;  //文件创建时间
    time_t time_access;  //文件上一次访问时间
    time_t time_write;   //文件上一次修改时间
    _fsize_t size;  //文件字节数
    char name[_MAX_FNAME]; //文件名
};

文件属性是无符号整数,取值为相应的宏:_A_ARCH(存档),_A_SUBDIR(文件夹),_A_HIDDEN(隐藏),_A_SYSTEM(系统),_A_NORMAL(正常),_A_RDONLY(只读)。容易看出,通过这个结构体,我们可以得到关于该文件的很多信息。结合以下函数,我们可以将文件信息存储到这个结构体中:

//按FileName命名规则匹配当前目录第一个文件
_findfirst(_In_ const char * FileName, _Out_ struct _finddata64i32_t * _FindData); 
 //按FileName命名规则匹配当前目录下一个文件
_findnext(_In_ intptr_t _FindHandle, _Out_ struct _finddata64i32_t * _FindData);
 //关闭_findfirst返回的文件句柄
_findclose(_In_ intptr_t _FindHandle);


_findfirst 函数返回的是匹配到文件的句柄,数据类型为long。遍历过程可以指定文件类型。

实例

#include <iostream>
#include <string>
#include <io.h>
using namespace std;

//遍历当前目录下的文件夹和文件,默认是按字母顺序遍历
bool TraverseFiles(string path,int &file_num)
{
    _finddata_t file_info;
    string current_path=path+"/*.*"; //可以定义后面的后缀为*.exe,*.txt等来查找特定后缀的文件,*.*是通配符,匹配所有类型,路径连接符最好是左斜杠/,可跨平台
    //打开文件查找句柄
    int handle=_findfirst(current_path.c_str(),&file_info);
    //返回值为-1则查找失败
    if(-1==handle)
        return false;
    do
    {
        //判断是否子目录
        string attribute;
        if(file_info.attrib==_A_SUBDIR) //是目录
            attribute="dir";
        else
            attribute="file";
        //输出文件信息并计数,文件名(带后缀)、文件最后修改时间、文件字节数(文件夹显示0)、文件是否目录
        cout<<file_info.name<<' '<<file_info.time_write<<' '<<file_info.size<<' '<<attribute<<endl; //获得的最后修改时间是time_t格式的长整型,需要用其他方法转成正常时间显示
        file_num++;

    }while(!_findnext(handle,&file_info));  //返回0则遍历完
    //关闭文件句柄
    _findclose(handle);
    return true;
}

//深度优先递归遍历当前目录下文件夹和文件及子文件夹和文件
void DfsFolder(string path,int layer)
{
    _finddata_t file_info;
    string current_path=path+"/*.*"; //也可以用/*来匹配所有
    int handle=_findfirst(current_path.c_str(),&file_info);
    //返回值为-1则查找失败
    if(-1==handle)
    {
        cout<<"cannot match the path"<<endl;
        return;
    }

    do
    {
        //判断是否子目录
        if(file_info.attrib==_A_SUBDIR)
        {
            //递归遍历子目录
            //打印记号反映出深度层次
            for(int i=0;i<layer;i++)
                cout<<"--";
            cout<<file_info.name<<endl;
            int layer_tmp=layer;
            if(strcmp(file_info.name,"..")!=0&&strcmp(file_info.name,".")!=0)  //.是当前目录,..是上层目录,必须排除掉这两种情况
                DfsFolder(path+'/'+file_info.name,layer_tmp+1); //再windows下可以用\\转义分隔符,不推荐
        }
        else
        {
            //打印记号反映出深度层次
            for(int i=0;i<layer;i++)
                cout<<"--";
            cout<<file_info.name<<endl;
        }
    }while(!_findnext(handle,&file_info));  //返回0则遍历完
    //关闭文件句柄
    _findclose(handle);
}

int main(int argc,char *argv[])
{
    //遍历单个目录
    int file_num=0;
    if(!TraverseFiles("E:/android-ndk",file_num))  //此处路径连接符只能用/,根盘符大小写都行
        cout<<"traverse files failed"<<endl;
    cout<<"-------------------\n"<<"file number: "<<file_num<<endl;

    //递归遍历文件夹
    DfsFolder("E:/personal_profile/tinyxml",0);
    return 0;
}

(ps:貌似注释多了点,有点碍眼T_T)
 

  • 14
    点赞
  • 58
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值