我想要一种在C++/Linux中创建多个目录的简单方法.
例如,我想在目录中保存文件lola.file:
/tmp/a/b/c
但如果目录不存在,我希望它们能够自动创建.一个工作的例子是完美的.
使用Boost.Filesystem很容易: create_directories
#include//... boost::filesystem::create_directories("/tmp/a/b/c");
返回:true
如果创建了新目录,否则返回false
.
这是一个可以用C++编译器编译的C函数.
/* @(#)File: $RCSfile: mkpath.c,v $ @(#)Version: $Revision: 1.13 $ @(#)Last changed: $Date: 2012/07/15 00:40:37 $ @(#)Purpose: Create all directories in path @(#)Author: J Leffler @(#)Copyright: (C) JLSS 1990-91,1997-98,2001,2005,2008,2012 */ /*TABSTOP=4*/ #include "jlss.h" #include "emalloc.h" #include#ifdef HAVE_UNISTD_H #include #endif /* HAVE_UNISTD_H */ #include #include "sysstat.h" /* Fix up for Windows - inc mode_t */ typedef struct stat Stat; #ifndef lint /* Prevent over-aggressive optimizers from eliminating ID string */ const char jlss_id_mkpath_c[] = "@(#)$Id: mkpath.c,v 1.13 2012/07/15 00:40:37 jleffler Exp $"; #endif /* lint */ static int do_mkdir(const char *path, mode_t mode) { Stat st; int status = 0; if (stat(path, &st) != 0) { /* Directory does not exist. EEXIST for race condition */ if (mkdir(path, mode) != 0 && errno != EEXIST) status = -1; } else if (!S_ISDIR(st.st_mode)) { errno = ENOTDIR; status = -1; } return(status); } /** ** mkpath - ensure all directories in path exist ** Algorithm takes the pessimistic view and works top-down to ensure ** each directory in path exists, rather than optimistically creating ** the last element and working backwards. */ int mkpath(const char *path, mode_t mode) { char *pp; char *sp; int status; char *copypath = STRDUP(path); status = 0; pp = copypath; while (status == 0 && (sp = strchr(pp, '/')) != 0) { if (sp != pp) { /* Neither root nor double slash in path */ *sp = '\0'; status = do_mkdir(copypath, mode); *sp = '/'; } pp = sp + 1; } if (status == 0) status = do_mkdir(path, mode); FREE(copypath); return (status); } #ifdef TEST #include /* ** Stress test with parallel running of mkpath() function. ** Before the EEXIST test, code would fail. ** With the EEXIST test, code does not fail. ** ** Test shell script ** PREFIX=mkpath.$$ ** NAME=./$PREFIX/sa/32/ad/13/23/13/12/13/sd/ds/ww/qq/ss/dd/zz/xx/dd/rr/ff/ff/ss/ss/ss/ss/ss/ss/ss/ss ** : ${MKPATH:=mkpath} ** ./$MKPATH $NAME & ** [...repeat a dozen times or so...] ** ./$MKPATH $NAME & ** wait ** rm -fr ./$PREFIX/ */ int main(int argc, char **argv) { int i; for (i = 1; i < argc; i++) { for (int j = 0; j < 20; j++) { if (fork() == 0) { int rc = mkpath(argv[i], 0777); if (rc != 0) fprintf(stderr, "%d: failed to create (%d: %s): %s\n", (int)getpid(), errno, strerror(errno), argv[i]); exit(rc == 0 ? EXIT_SUCCESS : EXIT_FAILURE); } } int status; int fail = 0; while (wait(&status) != -1) { if (WEXITSTATUS(status) != 0) fail = 1; } if (fail == 0) printf("created: %s\n", argv[i]); } return(0); } #endif /* TEST */
这些宏是STRDUP()
and FREE()
的错误检查版本,strdup()
并free()
在emalloc.h
(并在emalloc.c
和中实现estrdup.c
)声明.该"sysstat.h"
用的破碎版本头交易
,并且可以被替换为
现代Unix系统上(但在1990年出现了许多问题后).并"jlss.h"
宣布mkpath()
.
v1.12(上一个)和v1.13(上面)之间的变化是EEXIST
in 的测试do_mkdir()
.Switch指出这是必要的- 谢谢你,Switch.测试代码已经升级并在MacBook Pro(2.3GHz Intel Core i7,运行Mac OS X 10.7.4)上重现了问题,并建议在修订版中修复问题(但测试只能显示错误的存在) ,从不他们缺席).
(特此允许您将此代码用于任何归属目的.)
system("mkdir -p /tmp/a/b/c")
是我能想到的最短路径(就代码长度而言,不一定是执行时间).
它不是跨平台的,但可以在Linux下运行.
这是我的代码示例(适用于Windows和Linux):
#include#include #include // stat #include // errno, ENOENT, EEXIST #if defined(_WIN32) #include // _mkdir #endif bool isDirExist(const std::string& path) { #if defined(_WIN32) struct _stat info; if (_stat(path.c_str(), &info) != 0) { return false; } return (info.st_mode & _S_IFDIR) != 0; #else struct stat info; if (stat(path.c_str(), &info) != 0) { return false; } return (info.st_mode & S_IFDIR) != 0; #endif } bool makePath(const std::string& path) { #if defined(_WIN32) int ret = _mkdir(path.c_str()); #else mode_t mode = 0755; int ret = mkdir(path.c_str(), mode); #endif if (ret == 0) return true; switch (errno) { case ENOENT: // parent didn't exist, try to create it { int pos = path.find_last_of('/'); if (pos == std::string::npos) #if defined(_WIN32) pos = path.find_last_of('\\'); if (pos == std::string::npos) #endif return false; if (!makePath( path.substr(0, pos) )) return false; } // now, try to create again #if defined(_WIN32) return 0 == _mkdir(path.c_str()); #else return 0 == mkdir(path.c_str(), mode); #endif case EEXIST: // done! return isDirExist(path); default: return false; } } int main(int argc, char* ARGV[]) { for (int i=1; i 用法:
$ makePath 1/2 folderA/folderB/folderC creating 1/2 ... OK creating folderA/folderB/folderC ... OK
这个答案需要进行投票.很多.谢谢!
5> Paul Tomblin..:#include#include int status; ... status = mkdir("/tmp/a/b/c", S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); 从这里开始.您可能必须为/ tmp,/ tmp/a,/ tmp/a/b /然后/ tmp/a/b/c单独执行mkdirs,因为在C api中没有等效的-p标志.当你做上层的时候,一定要忽略EEXISTS错误.
6> phorgan1..:这与前一个类似,但是通过字符串向前工作而不是递归向后.为最后一次失败留下错误的正确值.如果有一个前导斜杠,那么循环中有一个额外的时间可以通过循环外的一个find_first_of()或通过检测前导/并将前置设置为1来避免.无论我们是否通过设置设置,效率都是相同的第一个循环或一个预循环调用,使用预循环调用时复杂度会略微提高.
#include#include #include int mkpath(std::string s,mode_t mode) { size_t pos=0; std::string dir; int mdret; if(s[s.size()-1]!='/'){ // force trailing / so we can handle everything in loop s+='/'; } while((pos=s.find_first_of('/',pos))!=std::string::npos){ dir=s.substr(0,pos++); if(dir.size()==0) continue; // if leading / first time is 0 length if((mdret=mkdir(dir.c_str(),mode)) && errno!=EEXIST){ return mdret; } } return mdret; } int main() { int mkdirretval; mkdirretval=mkpath("./foo/bar",0755); std::cout << mkdirretval << '\n'; }
7> mcsim..:应当注意,从C ++ 17文件系统接口开始是标准库的一部分。这意味着可以使用以下内容来创建目录:
#includestd::filesystem::create_directories("/a/b/c/d") 此处提供更多信息:https : //en.cppreference.com/w/cpp/filesystem/create_directory
另外,对于gcc,需要将CFLAGS设置为“ -std = c ++ 17”。和“ -lstdc ++ fs”到LDLIBS。将来可能不再需要后者。
8> Jason Cohen..:你说"C++"但是这里的每个人似乎都在想"Bash shell".
查看gnu的源代码
mkdir
; 那么你可以看到如何在C++中实现shell命令.
ChristopheD:system()很少是正确的答案.