(Window和linux下)c/c++如何遍历文件夹中的文件及子文件夹并改写文件名
Window
#include <iostream>
#include <string>
#include <io.h>
using namespace std;
//便于跨平台
#ifdef WIN32
#define oldname "C:\\Users\\TuZhou\\Desktop\\featurelib\\images"
#define newname "C:\\Users\\TuZhou\\Desktop\\featurelib\\images"
#else
#define oldname "/home/share_linux/featurelib/images/"
#define newname "/home/share_linux/featurelib/images/"
#endif
void findfile(string path, string mode)
{
_finddata_t file;
intptr_t HANDLE;
string Onepath = path + mode;
HANDLE = _findfirst(Onepath.c_str(), &file);
if (HANDLE == -1L)
{
cout << "can not match the folder path" << endl;
system("pause");
}
cout << "success open file" << endl;
//int i = 1;
do {
//判断是否为"."当前目录,".."上一层目录
if ((strcmp(file.name, ".") == 0) || (strcmp(file.name, "..") == 0))
{
continue;
}
//判断是否有子目录
if (file.attrib & _A_SUBDIR)
{
string newPath = path + "\\" + file.name;
//cout << newPath << endl;
findfile(newPath,mode);
}
else
{
cout << file.name << " " << endl;
// string s = oldname;
// s = s + file.name;
//strcat(s, file.name);
//string id =path + to_string(i++) + ".jpg";
//rename(s.c_str(), id.c_str());
}
} while (_findnext(HANDLE, &file) == 0);
_findclose(HANDLE);
}
int main(int argc, char **argv)
{
string mode = "\\*.*";
string path = oldname;
findfile(path,mode);
return 0;
}
其中#ifdef WIN32是便于跨平台使用,此处可以不加,不过也只是记录一下,如果是64位系统也没问题,毕竟64位可以向32位兼容,64位win也可以写成#ifdef WIN64但是若是32位系统就无法使用。
核心部分使用c++中的_finddata_t 结构体,必须要加上io.h头文件。
关于_finddata_t 中的attrib为读取到文件的属性,该值和_A_SUBDIR进行&操作的结果为真的话,代表读取到的是个文件夹,此时就递归进入文件夹里继续读取。
详细可参考_finddata_t结构体等描述
更改文件名很简单,直接使用一个函数就行
rename(oldName.c_str(), newName.c_str())
参数均为const char*类型,可用string定义使用c_str()函数转换。
参考自c++修改文件名
main函数中的string mode = "\\*.*"
其中*.*
为文件路径中的通配符,*
代表0个或多个任意字符,.*
表示的是该目录下所有类型文件和目录以及”.”
,".."
。
注意_findfirst打开的路径必须是要加上这个通配符的,否则你打开读取的文件名还是该文件夹本身,容易无限读取。
详细可参考
文件目录通配符
路径通配符
linux
老规矩先贴代码
#include <iostream>
#include <stdio.h>
#include <unistd.h>
#include <dirent.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <string.h>
using namespace std;
#define images_dir "./images"
/***** Global Variables *****/
/* Show all files under dir_name , do not show directories ! */
void showAllFiles( string dir_name )
{
// check the parameter !
if(dir_name.empty())
{
cout<<" dir_name is null ! "<<endl;
return;
}
// check if dir_name is a valid dir
struct stat s;
lstat( dir_name.c_str() , &s );
if( ! S_ISDIR( s.st_mode ) )
{
cout<<"dir_name is not a valid directory !"<<endl;
return;
}
struct dirent * filename; // return value for readdir()
DIR * dir; // return value for opendir()
dir = opendir( dir_name.c_str() );
if( NULL == dir )
{
cout<<"Can not open dir "<<dir_name<<endl;
return;
}
//cout<<"Successfully opened the dir !"<<endl;
/* read all the files in the dir ~ */
int face_index = 1;
while( ( filename = readdir(dir) ) != NULL )
{
//get rid of "." and ".."
if( strcmp( filename->d_name , "." ) == 0 ||
strcmp( filename->d_name , "..") == 0 )
continue;
if(filename->d_type == 4)
{
//cout << filename->d_name << endl;
showAllFiles(dir_name + "/" + filename->d_name + "/");
}
else
cout<<filename ->d_name <<endl;
}
}
int main()
{
string dir = images_dir;
// 测试
showAllFiles( dir );
return 0;
}
请注意,无论是window下和linux下的文件遍历代码,在while循环中我都加了这么一个判断:
if( strcmp( filename->d_name , "." ) == 0 || strcmp( filename->d_name , "..") == 0 )
这个是判断当前读取到的文件名是否是"."
或者是".."
,前者代表的是当前目录,后者代表的是上一目录,每个文件夹中都包含有这两个隐藏目录,就像一个是文件夹的入口,一个是文件夹的出口。当读取文件夹时会先读取到这两个隐藏目录,所以遇到直接continue。
在linux下使用的文件方法与window下不同,关于stat,dirent等类型的解释可参考:
stat方法类型
dirent及文件操作方法
DIR目录流类型
更改文件名同样可使用rename函数。
在while循环中的这段代码:
if(filename->d_type == 4)
这里d_type为代表读取到的文件属性,当其为4时代表读到的是个文件夹,所以进入递归继续往里读。
关于dirent的d_type属性更多介绍请参考:
d_type属性
暂记到此,如有过错,敬请批正。