Lip*_*pis 104 c++ linux directory
我想要一种在C++/Linux中创建多个目录的简单方法.
例如,我想在目录中保存文件lola.file:
/tmp/a/b/c
Run Code Online (Sandbox Code Playgroud)
但如果目录不存在,我希望它们能够自动创建.一个工作的例子是完美的.
Ben*_*oît 154
使用Boost.Filesystem很容易: create_directories
#include <boost/filesystem.hpp>
//...
boost::filesystem::create_directories("/tmp/a/b/c");
Run Code Online (Sandbox Code Playgroud)
返回:true如果创建了新目录,否则返回false.
Jon*_*ler 58
这是一个可以用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 <errno.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif /* HAVE_UNISTD_H */
#include <string.h>
#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 <stdio.h>
/*
** 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 */
Run Code Online (Sandbox Code Playgroud)
这些宏是STRDUP()and FREE()的错误检查版本,strdup()并free()在emalloc.h(并在emalloc.c和中实现estrdup.c)声明.该"sysstat.h"用的破碎版本头交易<sys/stat.h>,并且可以被替换为<sys/stat.h>现代Unix系统上(但在1990年出现了许多问题后).并"jlss.h"宣布mkpath().
v1.12(上一个)和v1.13(上面)之间的变化是EEXISTin 的测试do_mkdir().Switch指出这是必要的- 谢谢你,Switch.测试代码已经升级并在MacBook Pro(2.3GHz Intel Core i7,运行Mac OS X 10.7.4)上重现了问题,并建议在修订版中修复问题(但测试只能显示错误的存在) ,从不他们缺席).
(特此允许您将此代码用于任何归属目的.)
Chr*_*heD 37
system("mkdir -p /tmp/a/b/c")
Run Code Online (Sandbox Code Playgroud)
是我能想到的最短路径(就代码长度而言,不一定是执行时间).
它不是跨平台的,但可以在Linux下运行.
Max*_*lov 24
这是我的代码示例(适用于Windows和Linux):
#include <iostream>
#include <string>
#include <sys/stat.h> // stat
#include <errno.h> // errno, ENOENT, EEXIST
#if defined(_WIN32)
#include <direct.h> // _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<argc; i++)
{
std::cout << "creating " << ARGV[i] << " ... " << (makePath(ARGV[i]) ? "OK" : "failed") << std::endl;
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
用法:
$ makePath 1/2 folderA/folderB/folderC
creating 1/2 ... OK
creating folderA/folderB/folderC ... OK
Run Code Online (Sandbox Code Playgroud)
Pau*_*lin 23
#include <sys/types.h>
#include <sys/stat.h>
int status;
...
status = mkdir("/tmp/a/b/c", S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
Run Code Online (Sandbox Code Playgroud)
从这里开始.您可能必须为/ tmp,/ tmp/a,/ tmp/a/b /然后/ tmp/a/b/c单独执行mkdirs,因为在C api中没有等效的-p标志.当你做上层的时候,一定要忽略EEXISTS错误.
这与前一个类似,但是通过字符串向前工作而不是递归向后.为最后一次失败留下错误的正确值.如果有一个前导斜杠,那么循环中有一个额外的时间可以通过循环外的一个find_first_of()或通过检测前导/并将前置设置为1来避免.无论我们是否通过设置设置,效率都是相同的第一个循环或一个预循环调用,使用预循环调用时复杂度会略微提高.
#include <iostream>
#include <string>
#include <sys/stat.h>
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';
}
Run Code Online (Sandbox Code Playgroud)
应当注意,从C ++ 17文件系统接口开始是标准库的一部分。这意味着可以使用以下内容来创建目录:
#include <filesystem>
std::filesystem::create_directories("/a/b/c/d")
Run Code Online (Sandbox Code Playgroud)
此处提供更多信息:https : //en.cppreference.com/w/cpp/filesystem/create_directory
另外,对于gcc,需要将CFLAGS设置为“ -std = c ++ 17”。和“ -lstdc ++ fs”到LDLIBS。将来可能不再需要后者。
你说"C++"但是这里的每个人似乎都在想"Bash shell".
查看gnu的源代码mkdir; 那么你可以看到如何在C++中实现shell命令.
bool mkpath( std::string path )
{
bool bSuccess = false;
int nRC = ::mkdir( path.c_str(), 0775 );
if( nRC == -1 )
{
switch( errno )
{
case ENOENT:
//parent didn't exist, try to create it
if( mkpath( path.substr(0, path.find_last_of('/')) ) )
//Now, try to create again.
bSuccess = 0 == ::mkdir( path.c_str(), 0775 );
else
bSuccess = false;
break;
case EEXIST:
//Done!
bSuccess = true;
break;
default:
bSuccess = false;
break;
}
}
else
bSuccess = true;
return bSuccess;
}
Run Code Online (Sandbox Code Playgroud)
所以我mkdirp()今天需要,发现这个页面上的解决方案过于复杂。因此,我写了一个相当短的片段,很容易被其他偶然发现这个线程的人复制进来,他们想知道为什么我们需要这么多行代码。
目录
#ifndef MKDIRP_H
#define MKDIRP_H
#include <sys/stat.h>
#define DEFAULT_MODE S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH
/** Utility function to create directory tree */
bool mkdirp(const char* path, mode_t mode = DEFAULT_MODE);
#endif // MKDIRP_H
Run Code Online (Sandbox Code Playgroud)
目录
#include <errno.h>
bool mkdirp(const char* path, mode_t mode) {
// const cast for hack
char* p = const_cast<char*>(path);
// Do mkdir for each slash until end of string or error
while (*p != '\0') {
// Skip first character
p++;
// Find first slash or end
while(*p != '\0' && *p != '/') p++;
// Remember value from p
char v = *p;
// Write end of string at p
*p = '\0';
// Create folder from path to '\0' inserted at p
if(mkdir(path, mode) == -1 && errno != EEXIST) {
*p = v;
return false;
}
// Restore path to it's former glory
*p = v;
}
return true;
}
Run Code Online (Sandbox Code Playgroud)
如果您不喜欢 const 转换和临时修改字符串,只需在之后执行 astrdup()和free()it。