136

I want an easy way to create multiple directories in C++/Linux.

For example I want to save a file lola.file in the directory:

/tmp/a/b/c

but if the directories are not there I want them to be created automagically. A working example would be perfect.

Lipis
  • 21,388
  • 20
  • 94
  • 121
  • C++ does not have any built-in facilities for creating directories and trees *per se*. You will have to use C and system calls or an external library like Boost. C and system calls will be platform dependent. – jww Jan 20 '14 at 14:22
  • 7
    @noloader Thanks a lot man.. but I think after 4 years I pretty much got my answer as you can see bellow in 13 different ways... – Lipis Jan 20 '14 at 17:47
  • Yeah, I was surprised no one explicitly stated you cannot do it in C++ (assuming you wanted a portable method in C++ that worked on Linux). But you probably knew that ;). There were a lot of good suggestions for non-portable C code, though. – jww Jan 20 '14 at 18:33
  • What is "C++/Linux"? – Lightness Races in Orbit Jan 22 '15 at 02:05
  • 3
    @LightnessRacesinOrbit It's my university years in C++ on Linux :) – Lipis Jan 23 '15 at 11:48

18 Answers18

175

Easy with Boost.Filesystem: create_directories

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

Returns: true if a new directory was created, otherwise false.

chappjc
  • 30,359
  • 6
  • 75
  • 132
Benoît
  • 16,798
  • 8
  • 46
  • 66
  • That's kind of nifty. How big an overheard is there including boost in a C++ project? – Paul Tomblin Mar 23 '09 at 20:46
  • It's nifty.. but won't work in my project.. it's an embedded linux system.. and I'm a noob so.. :) – Lipis Mar 23 '09 at 20:53
  • 9
    Well, most boost libraries are header-only, meaning there is no overhead besides what you use. In the case of Boost.Filesystem, it requires compiling though. On my disk, the compiled library weighs ~60KB. – Benoît Mar 23 '09 at 20:54
  • 1
    @Lipis: please precise what your embedded system is. I believe it should be available on pretty much every linux distribution. – Benoît Mar 23 '09 at 20:56
  • @Benoit: I guess you're right... Maybe I'll try it at one point! – Lipis Mar 23 '09 at 23:14
  • 1
    I'm starting to like Boost more and more every hour :) – Martin Ueding May 05 '13 at 11:18
  • 4
    Regarding on the C++11 compilers mentioned by @danijar, the comment [here](http://stackoverflow.com/a/12151364/693110) made it clearer: `The header is not part of C++11; it is a proposal for C++ TR2 based on the Boost.Filesystem library. Visual C++ 2012 includes an implementation of the proposed library.` – Chunliang Lyu Sep 04 '13 at 07:49
  • 5
    boost::filesystem is not header-only: http://stackoverflow.com/questions/13604090/list-of-header-only-boost-libraries – ftvs Nov 01 '13 at 03:15
  • This option requires you to compile the boost::filesystem, something that should not be recommended. – ABCD Apr 16 '15 at 05:13
  • 2
    IMHO: In any project of mine that is meant to do something significant and stand the test of time, it is WELL worth the compile to have such a set of incredibly useful and powerful standardized tools as boost. A ton of it has already made its way into standard C++, certainly with more to come. Try it out, stick with it, you'll benefit if you have more than trivial needs and you do not want to reinvent the wheel. :-) – moodboom Dec 09 '16 at 00:59
  • 1
    Caveat: compile times definitely go up. – moodboom Dec 09 '16 at 03:17
  • 1
    We have stdc++17 `fs::create_directories` now! – tigertang Jul 10 '19 at 05:23
93

With C++17 or later, there's the standard header <filesystem> with function std::filesystem::create_directories which should be used in modern C++ programs. The C++ standard functions do not have the POSIX-specific explicit permissions (mode) argument, though.

However, here's a C function that can be compiled with C++ compilers.

/*
@(#)File:           mkpath.c
@(#)Purpose:        Create all directories in path
@(#)Author:         J Leffler
@(#)Copyright:      (C) JLSS 1990-2020
@(#)Derivation:     mkpath.c 1.16 2020/06/19 15:08:10
*/

/*TABSTOP=4*/

#include "posixver.h"
#include "mkpath.h"
#include "emalloc.h"

#include <errno.h>
#include <string.h>
/* "sysstat.h" == <sys/stat.h> with fixup for (old) Windows - inc mode_t */
#include "sysstat.h"

typedef struct stat Stat;

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>
#include <unistd.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 */

The macros STRDUP() and FREE() are error-checking versions of strdup() and free(), declared in emalloc.h (and implemented in emalloc.c and estrdup.c). The "sysstat.h" header deals with broken versions of <sys/stat.h> and can be replaced by <sys/stat.h> on modern Unix systems (but there were many issues back in 1990). And "mkpath.h" declares mkpath().

The change between v1.12 (original version of the answer) and v1.13 (amended version of the answer) was the test for EEXIST in do_mkdir(). This was pointed out as necessary by Switch — thank you, Switch. The test code has been upgraded and reproduced the problem on a MacBook Pro (2.3GHz Intel Core i7, running Mac OS X 10.7.4), and suggests that the problem is fixed in the revision (but testing can only show the presence of bugs, never their absence). The code shown is now v1.16; there have been cosmetic or administrative changes made since v1.13 (such as use mkpath.h instead of jlss.h and include <unistd.h> unconditionally in the test code only). It's reasonable to argue that "sysstat.h" should be replaced by <sys/stat.h> unless you have an unusually recalcitrant system.

(You are hereby given permission to use this code for any purpose with attribution.)

This code is available in my SOQ (Stack Overflow Questions) repository on GitHub as files mkpath.c and mkpath.h (etc.) in the src/so-0067-5039 sub-directory.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • Ok... the result of that one exactly what I wanted..! Can someone tell me if this is faster than system("mkdir -p /tmp/a/b/c").. cause this is so much easier :) – Lipis Mar 23 '09 at 21:10
  • 2
    It surely is faster than system. System has a lot of overhead involved. Basically, the process has to be forked, then at least two binaries have to be loaded (one will probably be in cache already), on of which will be yet another fork of the other, ... – ypnos Mar 23 '09 at 21:55
  • 1
    I forgot: And then "mkdir -p" will do at least the same as the code posted above! – ypnos Mar 23 '09 at 21:56
  • 7
    There's a subtle race condition in this code that I actually hit. It only happens when multiple programs start up simultaneously and make the same folder path. The fix is to add `if (errno != EEXIST) { status = -1; }` when mkdir fails. – Switch Jul 14 '12 at 23:57
  • 2
    @Switch: Thanks. That's the trouble with using `stat()` before `mkdir()`; it is a TOCTOU (time of check, time of use) problem. I tried tickling the bug with a shell script running 13 processes in background creating the same 29-element path, and didn't manage to hit it. Then I hacked the test program to fork 20 times and have each child try, and that managed to hit the bug. The fixed code will have `if (mkdir(path, mode) != 0 && errno != EEXIST) status = -1;`. That doesn't show the bug. – Jonathan Leffler Jul 15 '12 at 00:43
  • 1
    Where can I find the jlss and emalloc libraries? My compiler errors out for these 2. – David Merinos Jan 14 '19 at 19:45
  • 2
    @DavidMerinos: they're headers (`jlss.h`, `emalloc.h`), not libraries. However, the code is available in my [SOQ](https://github.com/jleffler/soq) (Stack Overflow Questions) repository on GitHub as files `jlss.h`, `emalloc.c` and `emalloc.h` in the [src/libsoq](https://github.com/jleffler/soq/tree/master/src/libsoq) sub-directory. You'll need `posixver.h` too, and a few others (`debug.h`, `stderr.c`, `stderr.h` — I think that's it, but what you need should all be in that directory). – Jonathan Leffler Jan 14 '19 at 19:50
43
system("mkdir -p /tmp/a/b/c")

is the shortest way I can think of (in terms of the length of code, not necessarily execution time).

It's not cross-platform but will work under Linux.

einpoklum
  • 118,144
  • 57
  • 340
  • 684
ChristopheD
  • 112,638
  • 29
  • 165
  • 179
  • 2
    IF your going to give the solution as a shell command, it would be well to mention system (3) – dmckee --- ex-moderator kitten Mar 23 '09 at 20:19
  • 4
    Don't forget you'll need to escape the path properly if it's not controlled by you. Otherwise you would create a huge security hole. – Vlad Dec 07 '20 at 13:51
  • 4
    I wonder why people create so many APIs in WinAPI and Libc while you could create whole programs using system. Seriously why do this post has 42 upvotes, this is a major security issue and a terrible programming habit. – Nark Jul 29 '21 at 14:22
32

Here is my example of code (it works for both Windows and 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;
}

Usage:

$ makePath 1/2 folderA/folderB/folderC
creating 1/2 ... OK
creating folderA/folderB/folderC ... OK
Maxim Suslov
  • 4,335
  • 1
  • 35
  • 29
  • I second that comment! It is (surprisingly) not a trivial task to find a portable C++ way to create a directory. This answer needs more upvotes. – Manuel Lafond May 23 '17 at 16:35
  • 1
    Under Windows, isDirExist does not work if the trailing character is a backslash. Always returns false. I have to modify the code to: std::string dirPath(path); while ('\\' == *dirPath.rbegin()) dirPath.pop_back(); ... and then, of course, pass dirPath.c_str() in the call to _stat. – MiloDC Sep 08 '17 at 22:36
  • Windows API has "Non-ANSI names for compatibility" for `stat` (related to `__STDC__`) no need for the precompiler test. – Sandburg Aug 09 '19 at 12:24
28
#include <sys/types.h>
#include <sys/stat.h>

int status;
...
status = mkdir("/tmp/a/b/c", S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);

From here. You may have to do separate mkdirs for /tmp, /tmp/a, /tmp/a/b/ and then /tmp/a/b/c because there isn't an equivalent of the -p flag in the C api. Be sure and ignore the EEXISTS errno while you're doing the upper level ones.

Paul Tomblin
  • 179,021
  • 58
  • 319
  • 408
  • Fun fact: At least Solaris and HP/UX have mkdirp(), although it's clearly not optimal for portability. – Martin Carpenter Mar 23 '09 at 20:21
  • that's the point.. that I don't want to call all these functions separately. – Lipis Mar 23 '09 at 20:31
  • Calling mkdir a few times will be way, way faster than calling system once. – Paul Tomblin Mar 23 '09 at 20:38
  • I don't understand what you are suggesting: calling mkdir 4 times with different arguments? `("/tmp/",...)`, `("/tmp/a/",...)`, `("/tmp/a/b/",...)`, `("/tmp/a/b/c/",...)` – Antonio Apr 29 '16 at 08:58
  • @Antonio, that's exactly what I'm suggesting. 3 or 4 calls to `mkdir` are a lot more efficient than calling `system` once. However, if you have to make the `/tmp` directory, you've got bigger problems than I can help you with. – Paul Tomblin Apr 29 '16 at 12:00
  • As it is, this doesn't answer in a generic way to the question. For example, in a function `create_directories` taking the path as input, it would require preliminary splitting the input path. In [this solution](http://stackoverflow.com/a/675043/2436175), it's just a matter of concatenating 2 strings to create the system command call. – Antonio Apr 29 '16 at 13:45
  • Splitting a string into directories is trivial string processing. I didn't bother showing people how to do that because that wasn't the question. – Paul Tomblin Apr 29 '16 at 13:52
  • @PaulTomblin You didn't even show the *complete* code to answer the actual question. The complete code, includes all the calls to `mkdir` that I have mentioned in my previous comment. – Antonio Apr 29 '16 at 13:53
  • 1
    Again, it's pretty trivial to make the same call three times. The point is to give people enough information that they can write the code, not to write the code for them. – Paul Tomblin Apr 29 '16 at 13:57
24

It should be noted that starting from C++17 filesystem interface is part of the standard library. This means that one can have following to create directories:

#include <filesystem>

std::filesystem::create_directories("/a/b/c/d")

More info here: https://en.cppreference.com/w/cpp/filesystem/create_directory

Additionally, with gcc, one needs to "-std=c++17" to CFLAGS. And "-lstdc++fs" to LDLIBS. The latter potentially is not going to be required in the future.

mcsim
  • 1,647
  • 2
  • 16
  • 35
  • Should also work with new enough Visual C++ and "/std:c++latest". See: https://blogs.msdn.microsoft.com/vcblog/2018/05/07/announcing-msvc-conforms-to-the-c-standard/ and https://developercommunity.visualstudio.com/content/problem/296680/filesystem-is-not-a-member-of-std-1.html – Ron Burk Nov 21 '18 at 09:21
11

This is similar to the previous but works forward through the string instead of recursively backwards. Leaves errno with the right value for last failure. If there's a leading slash, there's an extra time through the loop which could have been avoided via one find_first_of() outside the loop or by detecting the leading / and setting pre to 1. The efficiency is the same whether we get set up by a first loop or a pre loop call, and the complexity would be (slightly) higher when using the pre-loop call.

#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';

}
lornova
  • 6,667
  • 9
  • 47
  • 74
phorgan1
  • 1,664
  • 18
  • 18
9

You said "C++" but everyone here seems to be thinking "Bash shell."

Check out the source code to gnu mkdir; then you can see how to implement the shell commands in C++.

Jason Cohen
  • 81,399
  • 26
  • 107
  • 114
7
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;
}
Mark
  • 768
  • 5
  • 12
5

So I need mkdirp() today, and found the solutions on this page overly complicated. Hence I wrote a fairly short snippet, that easily be copied in for others who stumble upon this thread an wonder why we need so many lines of code.

mkdirp.h

#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

mkdirp.cpp

#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;
}

If you don't like const casting and temporarily modifying the string, just do a strdup() and free() it afterwards.

slashmais
  • 7,069
  • 9
  • 54
  • 80
jonasfj
  • 2,349
  • 2
  • 24
  • 22
  • Posted to a gist too, so I don't forget where I put it next time a need it :) https://gist.github.com/jonasfj/7797272 – jonasfj Dec 04 '13 at 23:11
  • 2
    It is evil to try modifying a string that is passed as a constant. All else apart, it is likely to lead to dramatic failures if it is ever passed a string literal. – Jonathan Leffler Jun 22 '15 at 14:45
  • 2
    Perfectly right.... this is actually bad... probably strcpy would make this better... – jonasfj Jun 23 '15 at 21:10
3

Since this post is ranking high in Google for "Create Directory Tree", I am going to post an answer that will work for Windows — this will work using Win32 API compiled for UNICODE or MBCS. This is ported from Mark's code above.

Since this is Windows we are working with, directory separators are BACK-slashes, not forward slashes. If you would rather have forward slashes, change '\\' to '/'

It will work with:

c:\foo\bar\hello\world

and

c:\foo\bar\hellp\world\

(i.e.: does not need trailing slash, so you don't have to check for it.)

Before saying "Just use SHCreateDirectoryEx() in Windows", note that SHCreateDirectoryEx() is deprecated and could be removed at any time from future versions of Windows.

bool CreateDirectoryTree(LPCTSTR szPathTree, LPSECURITY_ATTRIBUTES lpSecurityAttributes = NULL){
    bool bSuccess = false;
    const BOOL bCD = CreateDirectory(szPathTree, lpSecurityAttributes);
    DWORD dwLastError = 0;
    if(!bCD){
        dwLastError = GetLastError();
    }else{
        return true;
    }
    switch(dwLastError){
        case ERROR_ALREADY_EXISTS:
            bSuccess = true;
            break;
        case ERROR_PATH_NOT_FOUND:
            {
                TCHAR szPrev[MAX_PATH] = {0};
                LPCTSTR szLast = _tcsrchr(szPathTree,'\\');
                _tcsnccpy(szPrev,szPathTree,(int)(szLast-szPathTree));
                if(CreateDirectoryTree(szPrev,lpSecurityAttributes)){
                    bSuccess = CreateDirectory(szPathTree,lpSecurityAttributes)!=0;
                    if(!bSuccess){
                        bSuccess = (GetLastError()==ERROR_ALREADY_EXISTS);
                    }
                }else{
                    bSuccess = false;
                }
            }
            break;
        default:
            bSuccess = false;
            break;
    }

    return bSuccess;
}
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Andy
  • 12,859
  • 5
  • 41
  • 56
  • One little mod - if the path contains backslashes this doesn't work. Here: ` LPCTSTR szLast = _tcsrchr(szPathTree, '\\');` You just need to add this: ``` if (nullptr == szLast) { szLast = _tcsrchr(szPathTree, '/'); } ``` – Den-Jason Jan 28 '20 at 12:03
  • 1
    Thanks for the info. What happens if a path is mixed? i.e.: `c:\this\is\a/mixed/path\of\slashes` Typically Windows slashes are backslashes. What should happen is the caller should sanitize the path and ensure all slashes are proper before calling this method. – Andy Jan 28 '20 at 17:13
3

I know it's an old question but it shows up high on google search results and the answers provided here are not really in C++ or are a bit too complicated.

Please note that in my example createDirTree() is very simple because all the heavy lifting (error checking, path validation) needs to be done by createDir() anyway. Also createDir() should return true if directory already exists or the whole thing won't work.

Here's how I would do that in C++:

#include <iostream>
#include <string>

bool createDir(const std::string dir)
{
    std::cout << "Make sure dir is a valid path, it does not exist and create it: "
              << dir << std::endl;
    return true;
}

bool createDirTree(const std::string full_path)
{
    size_t pos = 0;
    bool ret_val = true;

    while(ret_val == true && pos != std::string::npos)
    {
        pos = full_path.find('/', pos + 1);
        ret_val = createDir(full_path.substr(0, pos));
    }

    return ret_val;
}

int main()
{
    createDirTree("/tmp/a/b/c");
    return 0;
}

Of course createDir() function will be system-specific and there are already enough examples in other answers how to write it for linux, so I decided to skip it.

Tom
  • 76
  • 4
2

So many approaches has been described here but most of them need hard coding of your path into your code. There is an easy solution for that problem, using QDir and QFileInfo, two classes of Qt framework. Since your already in Linux environment it should be easy to use Qt.

QString qStringFileName("path/to/the/file/that/dont/exist.txt");
QDir dir = QFileInfo(qStringFileName).dir();
if(!dir.exists()) {
        dir.mkpath(dir.path());
}

Make sure you have write access to that Path.

Mohammad Rahimi
  • 965
  • 5
  • 15
1

If dir does not exist, create it:

boost::filesystem::create_directories(boost::filesystem::path(output_file).parent_path().string().c_str()); 
TylerH
  • 20,799
  • 66
  • 75
  • 101
Frank
  • 505
  • 5
  • 14
1

Here's C/C++ recursive function that makes use of dirname() to traverse bottom-up the directory tree. It will stop as soon as it finds an existing ancestor.

#include <libgen.h>
#include <string.h>

int create_dir_tree_recursive(const char *path, const mode_t mode)
{
    if (strcmp(path, "/") == 0) // No need of checking if we are at root.
        return 0;

    // Check whether this dir exists or not.
    struct stat st;
    if (stat(path, &st) != 0 || !S_ISDIR(st.st_mode))
    {
        // Check and create parent dir tree first.
        char *path2 = strdup(path);
        char *parent_dir_path = dirname(path2);
        if (create_dir_tree_recursive(parent_dir_path, mode) == -1)
            return -1;

        // Create this dir.
        if (mkdir(path, mode) == -1)
            return -1;
    }

    return 0;
}
ravinsp
  • 4,150
  • 2
  • 32
  • 43
0

If you don't have C++17 yet and look for a platform agnostic solution, use ghc::filesystem. The header-ony code is compatible to C++17 (in fact a backport) and easy to migrate later on.

transistor
  • 649
  • 6
  • 11
-1
mkdir -p /dir/to/the/file

touch /dir/to/the/file/thefile.ending
-3

The others got you the right answer, but I thought I'd demonstrate another neat thing you can do:

mkdir -p /tmp/a/{b,c}/d

Will create the following paths:

/tmp/a/b/d
/tmp/a/c/d

The braces allow you to create multiple directories at once on the same level of the hierarchy, whereas the -p option means "create parent directories as needed".

rmeador
  • 25,504
  • 18
  • 62
  • 103
  • after seeing Paul's answer, I realize that I (and a lot of other people) misunderstood the question... – rmeador Mar 23 '09 at 20:17
  • If somebody can Just update this by changing to system("mkdir -p /tmp/a/{b,c}/d"), cause the questions is not about doing it in shell.. but through C++. – Lipis Mar 23 '09 at 20:38
  • I think {a,b} will work in both sh-derived and csh-derived shells. I'm not sure if it will work in a system() command, though. – Paul Tomblin Mar 23 '09 at 20:45
  • 1
    @Lipis: doing that via system() is not a good solution to the OP's question. @Andy: I'd never considered that before, but I just tested it by replacing "mkdir -p" with "echo" and it prints out "/tmp/a/b/d /tmp/a/c/d", which suggests it is the shell doing it, not mkdir. – rmeador Mar 23 '09 at 20:47
  • @rmeador: if it's not a good solution, do you have something else to suggest? I want to do that through C++... that's my issue not how to do that through shell.. – Lipis Mar 23 '09 at 20:49
  • @Lipis: there are plenty of other answers here that suggest how to do it through C++. I'm rather fond of Boost, so I like Benoît's answer. Paul's solution should also work, if your embedded system is very constrained. Btw, sorry for not noticing that you ARE the OP in my last comment :) – rmeador Mar 23 '09 at 21:00
  • Note that strict POSIX shells (`dash` etc) do not support brace expansion. – Jonathan Leffler Mar 19 '16 at 19:05