C ++ / Linux에서 디렉토리 트리를 어떻게 만들 수 있습니까?


109

C ++ / Linux에서 여러 디렉터리를 쉽게 만드는 방법을 원합니다.

예를 들어 lola.file 파일을 디렉토리에 저장하고 싶습니다.

/tmp/a/b/c

그러나 디렉토리가 없으면 자동으로 생성되기를 원합니다. 작동하는 예가 완벽 할 것입니다.


C ++는 내장 된 시설 디렉토리와 나무 만들기 위해이없는 그 자체를 . C 및 시스템 호출 또는 Boost와 같은 외부 라이브러리를 사용해야합니다. C 및 시스템 호출은 플랫폼에 따라 다릅니다.
jww

6
@noloader 덕분에 많은 사람 ..하지만 난 당신이 ... (13 개) 다른 방법으로 울부 짖는 볼 수 있듯이 나는 거의 내 대답을 얻었다 사년 후에 생각
리 피스

예, 아무도 C ++에서 할 수 없다고 명시 적으로 언급하지 않았습니다 (Linux에서 작동하는 C ++에서 이식 가능한 방법을 원한다고 가정). 그러나 당신은 아마 알고있을 것입니다.). 하지만 이식 불가능한 C 코드에 대한 좋은 제안이 많이있었습니다.
jww

"C ++ / Linux"란 무엇입니까?
궤도에서 가벼운 경주

3
이 : 리눅스에서 C 내 대학 년 ++의 @LightnessRacesinOrbit
리 피스

답변:


59

C ++ 17 이상 에서는 최신 C ++ 프로그램에서 사용해야 <filesystem>하는 함수가 std::filesystem::create_directories있는 표준 헤더 가 있습니다. 그러나 C ++ 표준 함수에는 POSIX 특정 명시 적 권한 (모드) 인수가 없습니다.

그러나 여기에 C ++ 컴파일러로 컴파일 할 수있는 C 함수가 있습니다.

/*
@(#)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 */

매크로 STRDUP()FREE()오류 검사의 버전입니다 strdup()free(), 선언 emalloc.h(및 구현에 emalloc.cestrdup.c). "sysstat.h"의 깨진 버전의 헤더 거래 <sys/stat.h> 및 교체 할 수있는 <sys/stat.h>현대적인 유닉스 시스템 (그러나 많은 문제가 1990 년에 다시 있었다). 그리고 "mkpath.h"선언합니다 mkpath().

를 v1.12 (응답의 원본)와 v1.13 (응답의 수정 된 버전) 사이의 변화에 대해 테스트 하였다 EEXIST에서 do_mkdir(). Switch가 필요하다고 지적했습니다 . 감사합니다. Switch. 테스트 코드가 업그레이드되어 MacBook Pro (2.3GHz Intel Core i7, Mac OS X 10.7.4 실행)에서 문제가 재현되었으며 수정 버전에서 문제가 수정되었음을 제안합니다 (그러나 테스트는 버그의 존재만을 보여줄 수 있음 , 절대 부재). 표시된 코드는 이제 v1.16입니다. v1.13 이후로 외관상 또는 관리적 변경 사항이 있습니다 (예 : 테스트 코드에만 무조건 포함 및 mkpath.h대신 사용 ). 비정상적으로 반항적 인 시스템이없는 한 대체해야 한다고 주장하는 것이 합리적 입니다.jlss.h<unistd.h>"sysstat.h"<sys/stat.h>

(귀하는 어떤 목적 으로든이 코드를 사용할 수있는 권한을 부여 받았습니다.)

이 코드는 GitHub의 SOQ (Stack Overflow Questions) 저장소에서 파일로 mkpath.c, mkpath.h(등) src / so-0067-5039 하위 디렉터리에 있습니다.


2
확실히 시스템보다 빠릅니다. 시스템에는 많은 오버 헤드가 있습니다. 기본적으로 프로세스는 분기되어야하며 최소한 두 개의 바이너리가로드되어야합니다 (하나는 이미 캐시에있을 것입니다). 그 중 하나는 다른 하나의 또 다른 분기가 될 것입니다. ...
ypnos

1
나는 잊었다 : 그리고 "mkdir -p"는 적어도 위에 게시 된 코드와 동일하게 할 것이다!
ypnos

7
이 코드에는 제가 실제로 맞은 미묘한 경쟁 조건이 있습니다. 여러 프로그램이 동시에 시작되고 동일한 폴더 경로를 만드는 경우에만 발생합니다. 수정 사항은 if (errno != EEXIST) { status = -1; }mkdir이 실패 할 때 추가하는 것 입니다.
스위치

2
@Switch : 감사합니다. 그것은 stat()전에 사용하는 문제입니다 mkdir(). TOCTOU (체크 시간, 사용 시간) 문제입니다. 동일한 29 개 요소 경로를 생성하는 백그라운드에서 13 개의 프로세스를 실행하는 셸 스크립트로 버그를 간지럽 히려고 시도했지만 문제를 해결하지 못했습니다. 그런 다음 테스트 프로그램을 해킹하여 20 번 포크하고 각 어린이에게 시도해 보았습니다. 그 결과 버그가 발생했습니다. 고정 코드에는 if (mkdir(path, mode) != 0 && errno != EEXIST) status = -1;. 그것은 버그를 보여주지 않습니다.
Jonathan Leffler 2012

2
@DavidMerinos : 라이브러리가 아니라 헤더 ( jlss.h, emalloc.h)입니다. 그러나 코드 내에서 사용할 수 SOQ 파일로 GitHub의에 (스택 오버플로 질문) 저장소 jlss.h, emalloc.c그리고 emalloc.hSRC / libsoq의 하위 디렉토리. 당신은해야합니다 posixver.h도, 그리고 몇 가지 다른 ( debug.h, stderr.c, stderr.h- 나는 당신이 모든 디렉토리에 있어야합니다 필요 그게 생각하지만).
Jonathan Leffler

157

Boost.Filesystem으로 쉽게 : create_directories

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

반환 값 : true새 디렉토리가 생성 된 경우, 그렇지 않은 경우 false.


9
글쎄, 대부분의 부스트 라이브러리는 헤더 전용이므로 사용하는 것 외에 오버 헤드가 없습니다. Boost.Filesystem의 경우에는 컴파일이 필요합니다. 내 디스크에서 컴파일 된 라이브러리의 무게는 ~ 60KB입니다.
Benoît

1
@Lipis : 임베디드 시스템이 무엇인지 정확히 알려주세요. 거의 모든 리눅스 배포판에서 사용할 수 있어야한다고 생각합니다.
Benoît

4
@danijar에 의해 언급 된 C ++ 11 컴파일러와 관련하여 여기에 있는 주석은 더 명확하게했습니다. The <filesystem> 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

5
boost :: filesystem은 헤더 전용이 아닙니다 : stackoverflow.com/questions/13604090/…
ftvs

2
IMHO : 중요한 일을하고 시간의 시험을 견디는 내 프로젝트에서 부스트와 같은 엄청나게 유용하고 강력한 표준화 도구 세트를 갖는 것은 컴파일 할 가치가 있습니다. 그 중 상당수는 이미 표준 C ++에 적용되었으며 앞으로 더 많은 정보가 제공 될 것입니다. 시도해보고, 고수하십시오. 사소한 필요 이상이 있고 바퀴를 재발 명하고 싶지 않은 경우 도움이 될 것입니다. :-)
moodboom

42
system("mkdir -p /tmp/a/b/c")

내가 생각할 수있는 가장 짧은 방법입니다 (반드시 실행 시간이 아니라 코드 길이 측면에서).

크로스 플랫폼은 아니지만 Linux에서 작동합니다.


1
솔루션을 쉘 명령으로 제공하려는 경우 system (3)
dmckee --- ex-moderator kitten

26
#include <sys/types.h>
#include <sys/stat.h>

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 errno를 반드시 무시하십시오.


재미있는 사실 : 적어도 Solaris와 HP / UX에는 mkdirp ()가 있지만 이식성에 최적 인 것은 아닙니다.
Martin Carpenter

이 모든 기능을 따로 호출하고 싶지 않다는 점이 포인트입니다.
Lipis

mkdir을 몇 번 호출하는 것이 시스템을 한 번 호출하는 것보다 훨씬 빠릅니다.
Paul Tomblin

나는 당신이 제안하는 것을 이해하지 못합니다 : 다른 인수로 mkdir을 4 번 호출합니까? ("/tmp/",...), ("/tmp/a/",...), ("/tmp/a/b/",...),("/tmp/a/b/c/",...)
안토니오

1
다시 말하지만, 같은 전화를 세 번하는 것은 매우 간단합니다. 요점은 사람들에게 코드를 작성하는 것이 아니라 코드를 작성할 수있는 충분한 정보를 제공하는 것입니다.
Paul Tomblin 2013

25

다음은 코드 예제입니다 (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;
}

용법:

$ makePath 1/2 folderA/folderB/folderC
creating 1/2 ... OK
creating folderA/folderB/folderC ... OK

나는 그 코멘트를 두 번째! (놀랍게도) 디렉토리를 생성하는 이식 가능한 C ++ 방법을 찾는 것은 사소한 작업이 아닙니다. 이 답변에는 더 많은 찬성 투표가 필요합니다.
Manuel Lafond

1
Windows에서 후행 문자가 백 슬래시이면 isDirExist가 작동하지 않습니다. 항상 false를 반환합니다. 코드를 다음과 같이 수정해야합니다. std :: string dirPath (path); while ( '\\'== * dirPath.rbegin ()) dirPath.pop_back (); ... 물론 _stat에 대한 호출에서 dirPath.c_str ()을 전달합니다.
MiloDC

Windows API에는 프리 컴파일러 테스트가 필요하지 않기 때문에 "호환성을위한 비 ANSI 이름"이 있습니다 stat(관련 __STDC__).
Sandburg

18

C ++ 17 파일 시스템 인터페이스에서 시작하는 것은 표준 라이브러리의 일부입니다. 이것은 디렉토리를 생성하기 위해 다음을 가질 수 있음을 의미합니다.

#include <filesystem>

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로. 후자는 잠재적으로 미래에 필요하지 않을 것입니다.


새로운 Visual C ++ 및 "/ std : c ++ latest"에서도 작동해야합니다. 참조 : blogs.msdn.microsoft.com/vcblog/2018/05/07/…developercommunity.visualstudio.com/content/problem/296680/…
Ron Burk

9

이것은 이전과 유사하지만 재귀 적으로 역방향이 아닌 문자열을 통해 앞으로 작동합니다. 마지막 실패에 대한 올바른 값으로 errno를 남깁니다. 선행 슬래시가있는 경우 루프 외부에서 하나의 find_first_of ()를 통해 또는 선행 /를 감지하고 pre를 1로 설정하여 피할 수 있었던 루프를 통해 추가 시간이 있습니다. 효율성은 a 첫 번째 루프 또는 사전 루프 호출이며 사전 루프 호출을 사용할 때 복잡성이 (약간) 높아집니다.

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

}

7

"C ++"라고 하셨는데 여기 계신 분들은 모두 "Bash shell"을 생각하시는 것 같습니다.

gnu에 대한 소스 코드를 확인하십시오 mkdir. 그러면 C ++에서 쉘 명령을 구현하는 방법을 볼 수 있습니다.


시스템 ( "mkdir ...")은 리눅스에서 트릭을해야합니다. 그래도 크로스 플랫폼이 아닙니다.
ChristopheD

나는 @MartinCarpenter가 말한 것을 두 번째로
Joshua Hedges

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

나에게 가장 적합한 솔루션입니다! 감사합니다!)))
neo

덤프 질문 일 수도 있지만 mkdir 앞의 "::"접두사는 무엇입니까?
Rayee Roded

1
답을 찾았습니다. ::는 글로벌 네임 스페이스 stackoverflow.com/questions/4269034/…
Rayee Roded

4

그래서 mkdirp()오늘이 필요 하고이 페이지의 솔루션이 지나치게 복잡하다는 것을 알았습니다. 따라서 나는이 쓰레드를 우연히 발견 한 다른 사람들을 위해 쉽게 복사 할 수있는 상당히 짧은 스 니펫을 썼다. 우리가 왜 그렇게 많은 코드 라인이 필요한지 궁금해했다.

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

const 캐스팅을 좋아하지 않고 일시적으로 문자열을 수정하는 것이 마음에 들지 않으면 a strdup()를 수행 free()하고 나중에 수행하십시오.


나는 다음 시간 필요 그것을 :) 넣어 어디 잊지 않도록, 너무 요지에 게시 gist.github.com/jonasfj/7797272
jonasfj

2
상수로 전달되는 문자열을 수정하는 것은 나쁜 일입니다. 그 밖의 모든 사항을 제외하면 문자열 리터럴을 전달하면 극적인 실패로 이어질 수 있습니다.
Jonathan Leffler

2
완벽하게 잘 .... 이것은 아마도 strcpy를가 ...이 더 잘 만들 것 ... 실제로 나쁜
jonasfj

3

이 게시물은 "Create Directory Tree"에 대해 Google에서 높은 순위를 차지하고 있으므로 Windows에서 작동하는 답변을 게시 할 것입니다. 이것은 UNICODE 또는 MBCS 용으로 컴파일 된 Win32 API를 사용하여 작동합니다. 이것은 위의 Mark의 코드에서 이식되었습니다.

이것이 우리가 작업하는 Windows이기 때문에 디렉토리 구분 기호는 슬래시가 아니라 백 슬래시입니다. 슬래시를 사용하려면 다음 '\\'으로 변경하십시오 .'/'

다음과 함께 작동합니다.

c:\foo\bar\hello\world

c:\foo\bar\hellp\world\

(예 : 후행 슬래시가 필요하지 않으므로 확인할 필요가 없습니다.)

" Windows에서 SHCreateDirectoryEx () 를 사용하십시오"라고 말하기 전에 SHCreateDirectoryEx () 가 더 이상 사용되지 않으며 향후 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;
}

하나의 작은 모드-경로에 백 슬래시가 포함되어 있으면 작동하지 않습니다. 여기 :`LPCTSTR szLast = _tcsrchr (szPathTree, '\\');`다음을 추가하면됩니다.```if (nullptr == szLast) {szLast = _tcsrchr (szPathTree, '/'); }```
Den-Jason

1
정보 주셔서 감사합니다. 경로가 혼합되면 어떻게됩니까? 즉 : c:\this\is\a/mixed/path\of\slashes일반적으로 Windows 슬래시는 백 슬래시입니다. 호출자는이 메서드를 호출하기 전에 경로를 삭제하고 모든 슬래시가 적절한 지 확인해야합니다.
Andy

3

나는 그것이 오래된 질문이라는 것을 알고 있지만 그것은 Google 검색 결과에 높게 나타나고 여기에 제공된 답변은 실제로 C ++가 아니거나 너무 복잡합니다.

내 예제에서 createDirTree ()는 모든 무거운 작업 (오류 검사, 경로 유효성 검사)이 어쨌든 createDir ()에 의해 수행되어야하기 때문에 매우 간단합니다. 또한 createDir ()는 디렉토리가 이미 존재하거나 모든 것이 작동하지 않는 경우 true를 반환해야합니다.

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

물론 createDir () 함수는 시스템에 따라 다르며 다른 답변에는 이미 리눅스 용으로 작성하는 방법에 대한 충분한 예제가 있으므로 건너 뛰기로 결정했습니다.


1

dir이 없으면 작성하십시오.

boost::filesystem::create_directories(boost::filesystem::path(output_file).parent_path().string().c_str()); 

1

여기에는 많은 접근 방식이 설명되어 있지만 대부분은 코드 경로를 하드 코딩해야합니다. Qt 프레임 워크의 두 가지 클래스 인 QDir 및 QFileInfo를 사용하여이 문제에 대한 쉬운 해결책이 있습니다. 이미 Linux 환경에 있으므로 Qt를 사용하기 쉽습니다.

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

해당 경로에 대한 쓰기 액세스 권한이 있는지 확인하십시오.


0
mkdir -p /dir/to/the/file

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

-p옵션은 내가 무엇을 찾고있다. 감사!
asgs

0

다음 dirname()은 디렉토리 트리를 상향식으로 탐색 하는 데 사용하는 C / C ++ 재귀 함수 입니다. 기존 조상을 찾는 즉시 중지됩니다.

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

-2

다른 사람들은 당신에게 정답을 얻었지만 나는 당신이 할 수있는 또 다른 깔끔한 것을 보여줄 것이라고 생각했습니다.

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

다음 경로를 생성합니다.

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

중괄호를 사용하면 동일한 계층 수준에서 한 번에 여러 디렉터리를 만들 수 있지만 -p옵션은 "필요에 따라 부모 디렉터리 만들기"를 의미합니다.


Paul의 대답을 본 후, 나는 (그리고 많은 다른 사람들이) 질문을 오해했다는 것을 깨달았습니다 ...
rmeador

누군가 system ( "mkdir -p / tmp / a / {b, c} / d")으로 변경하여 이것을 업데이트 할 수 있다면 질문은 쉘에서 수행하는 것이 아니라 C ++를 통해 수행하는 것입니다.
Lipis

{a, b}는 sh 파생 쉘과 csh 파생 쉘 모두에서 작동한다고 생각합니다. 그래도 system () 명령에서 작동하는지 확실하지 않습니다.
Paul Tomblin

1
@Lipis : system ()을 통해 수행하는 것은 OP의 질문에 대한 좋은 해결책이 아닙니다. @Andy : 전에는 고려한 적이 없었지만 "mkdir -p"를 "echo"로 바꾸어 테스트했는데 "/ tmp / a / b / d / tmp / a / c / d"가 출력됩니다. 이는 mkdir이 아닌 쉘이 수행한다는 것을 나타냅니다.
rmeador

@rmeador : 좋은 해결책이 아니라면 다른 제안이 있습니까? 나는 C ++을 통해 그것을하고 싶다 ... 그것은 쉘을 통해서 그것을하는 방법이 아니라 나의 문제이다 ..
Lipis
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.