在最近做的一个项目中,需要一个获取一个文件夹下文件的功能,之前一直对文件的操作一直停留在对文件的读写,还从来没有接触过文件夹相关的操作。因此,这次有幸使用了,还是记录下来吧,以后肯定也会有很多使用的机会。
参考博客
C++ 文件/文件夹操作
1 本人项目中使用的方法(算比较蠢的吧,还是代码写的太少了。。)
需要使用dirent.h这个头文件,然后使用的基本流程是opendir ->readdir->closedir
和FILE类型不同,这里opendir返回的是DIR类型的指针。readdir返回的是struct dirent结构体类型。
结构体的详细内容如下:
struct dirent
{
#ifndef __USE_FILE_OFFSET64
__ino_t d_ino;
__off_t d_off;
#else
__ino64_t d_ino;
__off64_t d_off;
#endif
unsigned short int d_reclen;
unsigned char d_type;
char d_name[256]; /* We must not include limits.h! */
};
//查找path路径下的所有文件
vector<string> findFileNames(const char* path){
//用于保存文件名
vector<string> fileNames;
//dirent指针是一个结构体指针
struct dirent *ptr;
DIR *dir;
dir=opendir(path);
while((ptr=readdir(dir))!=NULL)
{
//跳过'.'和'..'两个目录
if(ptr->d_name[0] == '.')
continue;
fileNames.push_back(ptr->d_name);
}
closedir(dir);
return fileNames;
}
这个方法是适用于Linux下的文件操作,在Windows上测试会报头文件找不到。如果真的要使用的话需要去下载这个头文件,并放入VS的include文件夹下即可。
下载地址
dirent.h
2.filesystem库(和上一个相比,这个就和谐多了,是可移植的)
2.1 获取文件的一些属性
//注意 /= 和 += 的区别, /= 表示追加下级目录, += 仅仅是字符串的串接
path dir("C:\\Windows");
dir /= "System32"; //追加下级目录
dir /= "services.exe";
std::cout << dir << std::endl;
std::cout << dir.string() << std::endl; //转换成std::string 类型
std::cout << dir.root_name()<< std::endl; //盘符名:C:
std::cout << dir.root_directory()<< std::endl; //根目录:"\"
std::cout << dir.root_path()<< std::endl; //根路径:"C:\"
std::cout << dir.relative_path()<< std::endl; // 相对路径:Windows\System32\services.exe
std::cout << dir.parent_path()<< std::endl; //上级目录:C:\Windows\System32
std::cout << dir.filename()<< std::endl; //文件名:services.exe
std::cout << dir.stem()<< std::endl; //不带扩展的文件名:services
std::cout << dir.extension()<< std::endl; //扩展名:.exe
boost::filesystem::exists(file_path); //推断文件存在性
2.2文件的一些操作
#include "boost/filesystem.hpp"
#include <iostream>
#include <string>
//using namespace std;
int main(int argc, char *argv[])
{
std::string file_path = "/media/data_2/everyday/0902/test1";
if(boost::filesystem::exists(file_path)) //推断文件存在性
{
std::cout<<"file is exist"<<std::endl;
}
else
{
//文件夹不存在;
boost::filesystem::create_directory(file_path); //文件夹不存在。创建
}
std::string srcPath = "/media/data_2/everyday/0902/test.txt";
std::string destPath = "/media/data_2/everyday/0902/test1/1112.txt"; //需要具体到文件名,要不然报错
boost::filesystem::copy_file(srcPath , destPath);
//获取文件名
std::string srcPath = "/media/data_2/everyday/0902/test.txt";
boost::filesystem::path path_file(srcPath);
std::string file_name = path_file.filename().string();
std::cout<<file_name<<std::endl;// test.txt
return 1;
}
获取文件夹下所有文件名
#include "boost/filesystem.hpp"
#include <iostream>
#include <string>
//using namespace std;
int main(int argc, char *argv[])
{
boost::filesystem::path path("/media/data_2/everyday/0902/test2"); //初始化
boost::filesystem::path old_cpath = boost::filesystem::current_path(); //取得当前程序所在文件夹
boost::filesystem::path parent_path = old_cpath.parent_path();//取old_cpath的上一层父文件夹路径
boost::filesystem::path file_path = old_cpath / "file"; //path支持重载/运算符
if(boost::filesystem::exists(file_path)) //推断文件存在性
{
std::string strPath = file_path.string();
int x = 1;
}
else
{
//文件夹不存在;
boost::filesystem::create_directory(file_path); //文件夹不存在。创建
}
bool bIsDirectory = boost::filesystem::is_directory(file_path); //推断file_path是否为文件夹
boost::filesystem::recursive_directory_iterator beg_iter(file_path);
boost::filesystem::recursive_directory_iterator end_iter;
for (; beg_iter != end_iter; ++beg_iter)
{
if (boost::filesystem::is_directory(*beg_iter))
{
continue;
}
else
{
std::string strPath = beg_iter->path().string(); //遍历出来的文件名称
int x=1;
}
}
boost::filesystem::path new_file_path = file_path / "test.txt";
if(boost::filesystem::is_regular_file(new_file_path)) //推断是否为普通文件
{
int sizefile = boost::filesystem::file_size(new_file_path); //文件大小(字节)
int x =1;
}
boost::filesystem::remove(new_file_path);//删除文件new_file_path
return 1;
}
其他一些操作
//字符串和string类型作为参数,而提供的路径可以是相对路径,也可以是绝对路径。
boost::filesystem::path filePath(file);
//path的方法如filename()等,返回的对象仍是path,path的string()方法,获取string类型
//parent_path()获得的是当前文件的父路径
cout<<filePath.parent_path()<<endl; // "/home/test/cur/"
//filename()获得的是文件名,含拓展名
cout<<filePath.filename()<<endl; // "build.sh"
cout<<filePath.filename().string()<<endl;
//stem()获得的是文件的净文件名,即不含拓展名
cout<<filePath.stem()<<endl; // "build"
//拓展名(是".sh"而不是"sh")
cout<<filePath.extension()<<endl; // ".sh"
//获得文件的大小,单位为字节
int nFileSize = boost::filesystem::file_size(filePath);
//最后一次修改文件的时间
//last_write_time()返回的是最后一次文件修改的绝对秒数
//last_write_time(filePath,time(NULL))还可以修改文件的最后修改时间,相当于Linux中命令的touch
if(filePath.last_write_time() - time(NULL) > 5)
{
/*
*在工程实践中,当需要不断的扫目录,而目录又会不断的加入新文件时,
*借助last_write_time()可以判断新入文件的完整性,以避免处理未写完的文件
*/
}
//判断文件的状态信息
if(boost::filesystem::is_regular_file(file))
{
//is_regular_file(file)普通文件
//is_directory(file)目录文件,如当遍历到"/home/test/cur/src/"时,这就是一个目录文件
//is_symlink(file)链接文件
...
}
//更改拓展名
boost::filesystem::path tmpPath = filePath;
//假设遍历到了cpp文件,想看下对应的.o文件是否存在
tmpPath.replace_extension(".o");
//判断文件是否存在
if( boost::filesystem::exists( tmpPath.string() ) )
//删除文件
//remove只能删除普通文件,而不能删除目录
boost::filesystem::remove(tmpPath.string());
//remove_all则提供了递归删除的功能,可以删除目录
boost::filesystem::remove_all(tmpPath.string());
//移动文件 & 拷贝文件
//srcPath原路径,srcPath的类型为string
//destPath目标路径,destPath的类型为string
boost::filesystem::rename(srcPath , destPath);
boost::filesystem::copy_file(srcPath , destPath);
//拷贝目录
boost::filesystem::copy_files("/home/test","/dev/shm")
获取目录下所有文件名
#include <boost/filesystem.hpp>
namespace fs = boost::filesystem;
int get_filenames(const std::string& dir, std::vector<std::string>& filenames)
{
fs::path path(dir);
if (!fs::exists(path))
{
return -1;
}
fs::directory_iterator end_iter;
for (fs::directory_iterator iter(path); iter!=end_iter; ++iter)
{
if (fs::is_regular_file(iter->status()))
{
filenames.push_back(iter->path().string());
}
if (fs::is_directory(iter->status()))
{
get_filenames(iter->path().string(), filenames);
}
}
return filenames.size();
}