当前位置:  开发笔记 > 编程语言 > 正文

如何在C++/Linux中创建目录树?

如何解决《如何在C++/Linux中创建目录树?》经验,为你挑选了8个好方法。

我想要一种在C++/Linux中创建多个目录的简单方法.

例如,我想在目录中保存文件lola.file:

/tmp/a/b/c

但如果目录不存在,我希望它们能够自动创建.一个工作的例子是完美的.



1> Benoît..:

使用Boost.Filesystem很容易: create_directories

#include 
//...
boost::filesystem::create_directories("/tmp/a/b/c");

返回:true如果创建了新目录,否则返回false.


好吧,大多数boost库都是header-only,这意味着除了你使用的东西之外没有任何开销.在Boost.Filesystem的情况下,它需要编译.在我的磁盘上,编译的库重约60KB.
boost :: filesystem不是仅限标题:http://stackoverflow.com/questions/13604090/list-of-header-only-boost-libraries
关于@danijar提到的C++ 11编译器,注释[here](http://stackoverflow.com/a/12151364/693110)更清楚:`头不是C++的一部分11; 它是基于Boost.Filesystem库的C++ TR2提案.Visual C++ 2012包含了所提议库的实现
恕我直言:在我的任何项目中,要做一些重要的事情并经得起时间的考验,编译中有这么一套非常有用和强大的标准化工具作为提升是值得的.已经有很多它已经进入标准C++,当然还有更多.尝试一下,坚持下去,如果你有更多的琐碎需求并且你不想重新发明轮子,你将受益.:-)

2> Jonathan Lef..:

这是一个可以用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(上面)之间的变化是EEXISTin 的测试do_mkdir().Switch指出这是必要的- 谢谢你,Switch.测试代码已经升级并在MacBook Pro(2.3GHz Intel Core i7,运行Mac OS X 10.7.4)上重现了问题,并建议在修订版中修复问题(但测试只能显示错误的存在) ,从不他们缺席).

(特此允许您将此代码用于任何归属目的.)


这个代码中有一个微妙的竞争条件,我实际上已经击中了.它只发生在多个程序同时启动并生成相同的文件夹路径时.修复是添加`if(errno!= EEXIST){status = -1; 当mkdir失败时.
它肯定比系统更快.系统涉及很多开销.基本上,进程必须分叉,然后必须至少加载两个二进制文件(一个可能已经在缓存中),其中另一个是另一个的另一个分支,...
@Switch:谢谢.这是在`mkdir()`之前使用`stat()`的麻烦; 这是TOCTOU(检查时间,使用时间)问题.我尝试使用在后台运行13个进程的shell脚本来创建相同的29个元素的路径,并且无法点击它.然后我把测试程序分成20次,让每个孩子尝试,然后设法击中了这个bug.固定代码将具有`if(mkdir(path,mode)!= 0 && errno!= EEXIST)status = -1;`.这没有显示错误.
@DavidMerinos:它们是头文件(jlss.h,emalloc.h),而不是库。但是,该代码在GitHub上的[SOQ](https://github.com/jleffler/soq)(堆栈溢出问题)存储库中可用,分别为文件`jlss.h`,`emalloc.c`和`emalloc.h。在[src / libsoq](https://github.com/jleffler/soq/tree/master/src/libsoq)子目录中。您还需要`posixver.h`,以及其他一些(`debug.h`,`stderr.c`,`stderr.h-我想就是这样,但是您所需要的都应该在该目录中) 。

3> ChristopheD..:
system("mkdir -p /tmp/a/b/c")

是我能想到的最短路径(就代码长度而言,不一定是执行时间).

它不是跨平台的,但可以在Linux下运行.



4> Maxim Suslov..:

这是我的代码示例(适用于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文件系统接口开始是标准库的一部分。这意味着可以使用以下内容来创建目录:

#include 

std::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()很少是正确的答案.
推荐阅读
mobiledu2402851323
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有