admin管理员组文章数量:1660125
最近要写一个新建和删除文件夹操作的控制代码,由于以前没怎么接触过系统层级的编程,因此对这方面了解很少。比较了解的也只有C语言中的FILE*、fopen;和C++中的fstream。但这也只能在已有的目录下新建文件。
由于查资料时有很多代码都多多少少存在问题,因此我结合搜索到的有关解释和自己的测试,将解新建和删除文件夹(文件)的办法整合,且实现跨平台(Windows & Linux),希望对大家有帮助。
2022年3月补充:后来发现c++17的STL里包含了创建文件夹的库:std::filesystem::create_directory可以直接跨平台调用,无需调用后文所述的底层库^_^。https://en.cppreference/w/cpp/filesystem/create_directory
一、相关库函数及头文件
对文件夹的操作基本是和平台相关的!因此首先介绍一下各平台需要的库函数以及所在的头文件。内容有点多,不需要可直接看代码。
1、功能:新建文件夹
Windows
形式:_mkdir(const char *_Path);
头文件:#include <direct.h>
输入参数:_Path=创建新文件夹的路径及文件夹名,如"E:\study\math",新建文件夹的路径为"E:\study",新建文件夹名为"math"
说明:若新建文件夹的路径存在,且路径下没有同名文件夹或文件,则可成功创建一个空文件夹,并返回0,否则返回-1。因此不能一次性创建多级目录!新建多级目录需要一级一级地新建。ps:Windows上的函数大多前面加了下划线。mkdir前面若不加下划线"_",vs上编译报错并给出“不赞成用POSIX名称"mkdir",应该用ISO c/c++名称“_mkdir””。具体原因由于本人才疏学浅也不知道,有牛人知道的欢迎评论交流~
Linux
形式:mkdir(const char *_Path, mode_t mode);
头文件:#include <sys/stat.h>
输入参数:_Path=新文件夹的路径和文件夹名,同_mkdir。mode=新建目录的权限一般设为0755,mode内容有点多,0755是从别的地方搬过来的,测试可用,详细内容在此不叙述。
说明:除了多了个输入参数,其余基本同Windows中的_mkdir
2、功能:删除空文件夹
Windows
形式:_rmdir(const char *_Path);
头文件:#include <direct.h>
输入参数:_Path=需删除的空文件夹的路径及文件夹名,如“E:\study\math”,删除“E:\study”目录下,名为“math”的空文件夹。
说明:若输入参数路径存在,且被删除文件夹是一个空文件夹,则可成功删除该空文件夹,返回0,否则返回-1。因此要想删除某文件夹需要先删除文件夹内的文件和文件夹!代码部分会详述。
Linux
形式:rmdir(const char *_Path);
头文件:#include <unistd.h>
输入参数:_Path=需删除的空文件夹的路径及文件夹名,同_rmdir。
说明:主意头文件与mkdir不同
3、功能:检查文件夹(文件)的性质(主要检查是否存在)
Windows
形式:_access(const char *_FileName, int _AccessMode);
头文件:#include <io.h>
参数:_FileName=要检测的文件夹(文件)的路径,如“E:/study/math”,无论“math”是文件夹还是文件,都同样返回检测结果。_AccessMode=要检测的性质,主要赋0,检测是否存在。
说明:存在返回0,不存在返回-1。建立多级目录时可检测路径是否存在。
Linux
形式:access(const char *_FileName, int _AccessMode);
头文件:#include <unistd.h>
参数:同_access
说明:同_access
4、功能:删除文件
Windows、Linux上的形式、用法都一样
形式:remove(const char *_FileName);
头文件:stdio.h(Windows和Linux)、io.h(仅Windows)
参数:_FileName=需要删除的文件路径和文件名
说明:该函数只能删除文件,不能删除文件夹,删除成功返回0,失败返回-1.
5. 功能:遍历文件夹中的文件
Windows通过正则化匹配
函数:_findfirst(const char *_FileName, _finddata_t* _FindData),_findnext(intptr_t handle, _finddata_t* _FindData),_findclose(intptr_t handle)
结构体:_finddata_t。
头文件:io.h
具体用法看代码:
string findPath = "E:/study/math/*"; //*号为正则化语法,表示附加任意字符的可匹配
struct _finddata_t fb; //查找相同属性文件的存储结构体
intptr_t handle; //正则化索引的句柄,用long类型会报错
handle = _findfirst(findPath.c_str(), &fb); //匹配的第一个文件
if (handle != -1L)
{
std::string pathTemp;
do//循环找到的文件
{
//系统有个系统文件,名为“..”和“.”,对它不做处理
if (strcmp(fb.name, "..")!=0 && strcmp(fb.name, ".")!=0)//对系统隐藏文件的处理标记
{
// do something
}
} while (0 == _findnext(handle, &fb));//判断放前面会失去第一个搜索的结果
//关闭文件夹,只有关闭了才能删除。找这个函数找了很久,标准c中用的是closedir
//经验介绍:一般产生Handle的函数执行后,都要进行关闭的动作。
_findclose(handle);
}
Linux通过打开文件夹读里面的文件:
函数:opendir(const char *_FileName),readdir(DIR* dir),closedir(DIR* dir)
结构体:DIR、dirent
头文件:dirent.h(有的地方说需要sys/type.h,但试了一下好像不需要)
具体用法看代码
string strPath = "E:/study/math/"
DIR *d = opendir(strPath.c_str());//打开这个目录
if (d != NULL)
{
struct dirent *dt = NULL;
while (dt = readdir(d))//逐个读取目录中的文件到dt
{
//系统有个系统文件,名为“..”和“.”,对它不做处理
if (strcmp(dt->d_name, "..")!=0 && strcmp(dt->d_name, ".")!=0)
{
//do something
}
}
closedir(d);
}
测试过Windows正则化匹配中,正反斜杠"\\"和“/”都是可以的,Linux中用"/"所以建议统一用“/”。
6、查看给定路径是文件还是文件夹
在删除文件夹时,清楚文件夹内部信息时需要用到。
Windows要用_finddata_t结构体的attrib属性;
Linux则要用到<sys/stat.h>头文件中的结构体stat、函数stat(为什么同名还不太清楚)和S_ISDIR()宏。
具体用法看最后的代码。
二、程序实现
1、程序应注意的问题
1)新建文件夹
- 新建文件夹若文件夹已存在,或新建文件夹路径中有个同名文件,则会新建失败,新建文件夹函数已经可以对该情况作出检测,因此这对程序没有影响。如新建文件夹“E:/study/math”,但该文件夹已经存在,或“E:/study”中已存在文件“math”,则创建失败。
- 故只用注意是否是新建多级文件夹。因此新建文件夹时需要对路径一级一级判断,判断是否存在路径中的这些文件夹,若不存在则需要新建。如新建文件夹“E:/study/math”,E盘中没有“study”文件夹,需要先新建“E:/study”,再建“E:/study/math”。
- 由于判断函数无法分辨是文件夹还是文件,新建多级文件夹时,若存在同名文件,文件夹创建失败。如:新建文件夹“E:/study/math”,若“E:/”中有个文件名为“study”,则新建文件夹失败。
2)删除文件夹
- 删除文件夹本身就不存在,或者要删除的路径是个文件,删除失败,删除空文件夹的函数已经可以对该情况作出检测,因此这对程序没有影响。如删除“E:/study/math”,但并没有该文件夹,或者“math”是个文件,则删除失败。
- 删除文件夹存在,但是文件夹非空,也就是文件夹里面还有文件或者文件夹。对于文件,我们可以用库函数直接删除,如果是文件夹,则可递归调用删除文件夹的方式。如要删除文件夹“E:/study”,文件夹里有文件“score.txt”和文件夹“math”,文件“score.txt”直接remove删除,文件夹“math”则递归删除文件夹“E:/study/math”。
2、代码
新建和删除文件夹两个函数,编译测试通过。
0)头文件和预处理
#include <stdio.h>
#include <string>
#include <string.h>
#include <iostream>
#ifdef _WIN32
#include <direct.h> //for mkdir rmdir
#include <io.h> //for access
#elif __linux__
#include <unistd.h> //for mkdir rmdir
#include <sys/stat.h> //for access
#include <dirent.h> //for DIR remove
#endif
#ifdef _WIN32
#define ACCESS _access
#define MKDIR(a) _mkdir((a))
#define RMDIR(a) _rmdir((a))
#elif __linux__
#define ACCESS access
#define MKDIR(a) mkdir((a),0755)
#define RMDIR(a) rmdir((a))
#endif
1)新建文件夹
bool MkDir(const std::string& strPath)
{
int i = 0;
int nDirLen = strPath.length();
if (nDirLen <= 0)
return false;
char *pDirTemp = new char[nDirLen + 4];
strPath.copy(pDirTemp, nDirLen + 1, 0);// +1 to copy '\0'
pDirTemp[nDirLen] = '\0';
//在末尾加'/'
if (pDirTemp[nDirLen - 1] != '\\' && pDirTemp[nDirLen - 1] != '/')
{
pDirTemp[nDirLen] = '/';
pDirTemp[nDirLen + 1] = '\0';
nDirLen++;
}
// 创建目录
for (i = 0; i < nDirLen; i++)
{
if (pDirTemp[i] == '\\' || pDirTemp[i] == '/')
{
pDirTemp[i] = '\0';//截断后面的子目录,逐级查看目录是否存在,若不存在则创建
//如果不存在,创建
int statu;
statu = ACCESS(pDirTemp, 0);
if (statu != 0)//可能存在同名文件导致没有创建
{
statu = MKDIR(pDirTemp);
if (statu != 0)//可能上级不是文件夹而是同名文件导致创建失败
{
return false;
}
}
//支持linux,将所有\换成/
pDirTemp[i] = '/';
}
}
delete[] pDirTemp;
return true;
}
2)删除文件夹
由于不大系统代码差异较大,代码通过编译指令分为Windows和Linux两个部分
bool RmDir(const std::string & path)
{
std::string strPath = path;
#ifdef _WIN32
struct _finddata_t fb; //查找相同属性文件的存储结构体
//制作用于正则化路径
if (strPath.at(strPath.length() - 1) != '\\' || strPath.at(strPath.length() - 1) != '/')
strPath.append("\\");
std::string findPath = strPath + "*";
intptr_t handle;//用long类型会报错
handle = _findfirst(findPath.c_str(), &fb);
//找到第一个匹配的文件
if (handle != -1L)
{
std::string pathTemp;
do//循环找到的文件
{
//系统有个系统文件,名为“..”和“.”,对它不做处理
if (strcmp(fb.name, "..")!=0 && strcmp(fb.name, ".")!=0)//对系统隐藏文件的处理标记
{
//制作完整路径
pathTemp.clear();
pathTemp = strPath + std::string(fb.name);
//属性值为16,则说明是文件夹,迭代
if (fb.attrib == _A_SUBDIR)//_A_SUBDIR=16
{
RmDir(pathTemp.c_str());
}
//非文件夹的文件,直接删除。对文件属性值的情况没做详细调查,可能还有其他情况。
else
{
remove(pathTemp.c_str());
}
}
} while (0 == _findnext(handle, &fb));//判断放前面会失去第一个搜索的结果
//关闭文件夹,只有关闭了才能删除。找这个函数找了很久,标准c中用的是closedir
//经验介绍:一般产生Handle的函数执行后,都要进行关闭的动作。
_findclose(handle);
}
//移除文件夹
return RMDIR(strPath.c_str())==0?true:false;
#elif __linux__
if (strPath.at(strPath.length() - 1) != '\\' || strPath.at(strPath.length() - 1) != '/')
strPath.append("/");
DIR *d = opendir(strPath.c_str());//打开这个目录
if (d != NULL)
{
struct dirent *dt = NULL;
while (dt = readdir(d))//逐个读取目录中的文件到dt
{
//系统有个系统文件,名为“..”和“.”,对它不做处理
if (strcmp(dt->d_name, "..")!=0 && strcmp(dt->d_name, ".")!=0)//判断是否为系统隐藏文件
{
struct stat st;//文件的信息
std::string fileName;//文件夹中的文件名
fileName = strPath + std::string(dt->d_name);
stat(fileName.c_str(), &st);
if (S_ISDIR(st.st_mode))
{
RmDir(fileName);
}
else
{
remove(fileName.c_str());
}
}
}
closedir(d);
}
return rmdir(strPath.c_str())==0?true:false;
#endif
}
全篇到此结束,全篇基本手打,如果觉得有点用可以点个赞~有什么看法欢迎讨论交流~
版权声明:本文标题:cc++跨平台实现新建删除文件夹(文件)及输出文件夹内所有文件名 内容由热心网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:https://www.elefans.com/xitong/1729845581a1215091.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论