मैं C ++ / Linux में निर्देशिका ट्री कैसे बना सकता हूं?


109

मुझे C ++ / Linux में कई निर्देशिकाएँ बनाने का एक आसान तरीका चाहिए।

उदाहरण के लिए मैं निर्देशिका में एक फ़ाइल lola.file को सहेजना चाहता हूं:

/tmp/a/b/c

लेकिन अगर निर्देशिका नहीं होती है तो मैं चाहता हूं कि वे स्वचालित रूप से बनाए जाएं। एक कामकाजी उदाहरण एकदम सही होगा।


सी ++ में निर्देशिका और पेड़ प्रति सेगमेंट बनाने के लिए कोई अंतर्निहित सुविधाएं नहीं हैं । आपको C और सिस्टम कॉल या Boost जैसी बाहरी लाइब्रेरी का उपयोग करना होगा। सी और सिस्टम कॉल प्लेटफॉर्म पर निर्भर होंगे।
jww

6
@noloader धन्यवाद एक बहुत आदमी .. लेकिन मुझे लगता है कि 4 साल बाद मुझे बहुत ज्यादा मेरा जवाब मिल गया है क्योंकि आप 13 अलग-अलग तरीकों से bellow देख सकते हैं ...
Lipis

हाँ, मुझे आश्चर्य हुआ कि किसी ने स्पष्ट रूप से यह नहीं कहा कि आप इसे C ++ में नहीं कर सकते (यह मानते हुए कि आप C ++ में एक पोर्टेबल विधि चाहते हैं जो लिनक्स पर काम करता है)। लेकिन आप शायद यह जानते थे;)। यद्यपि गैर-पोर्टेबल सी कोड के लिए बहुत सारे अच्छे सुझाव थे।
jww

"C ++ / Linux" क्या है?
ऑर्बिट

3
@LightnessRacesinOrbit यह मेरी यूनिवर्सिटी का साल है C ++ में लिनक्स पर :)
लिपिस

जवाबों:


59

C ++ 17 या उसके बाद के, <filesystem>फ़ंक्शन के साथ मानक हेडर है std::filesystem::create_directories जिसे आधुनिक C ++ प्रोग्राम में उपयोग किया जाना चाहिए। 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.cऔर estrdup.c)। "sysstat.h"की टूट संस्करणों के साथ शीर्ष लेख सौदों <sys/stat.h> और द्वारा बदला जा सकता है <sys/stat.h>आधुनिक यूनिक्स प्रणालियों पर (लेकिन कई मुद्दों 1990 में वापस वहाँ थे)। और "mkpath.h"घोषित करता है mkpath()

V1.12 (उत्तर के मूल संस्करण) और v1.13 (उत्तर की संशोधित संस्करण) के बीच बदलाव के लिए परीक्षण किया गया था EEXISTमें do_mkdir()। यह स्विच द्वारा आवश्यक के रूप में बताया गया था - धन्यवाद, स्विच। मैकबुक प्रो (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>जब तक आपके पास असामान्य रूप से पुनर्गणना प्रणाली नहीं होती है, तब तक इसे बदल दिया जाना चाहिए ।

(आप एट्रिब्यूशन के साथ किसी भी उद्देश्य के लिए इस कोड का उपयोग करने की अनुमति दी गई है।)

यह कोड मेरे SOQ (स्टैक ओवरफ्लो प्रश्न) GitHub पर फाइलों mkpath.cऔर mkpath.h(आदि) src / so-0067-5039 उप-निर्देशिका में उपलब्ध है।


2
यह निश्चित रूप से सिस्टम से तेज है। सिस्टम में बहुत सारे ओवरहेड शामिल हैं। असल में, प्रक्रिया को कांटा जाना है, फिर कम से कम दो बायनेरिज़ को लोड करना होगा (एक शायद पहले से ही कैश में होगा), जिस पर दूसरे का एक और कांटा होगा, ...
ypnos

1
मैं भूल गया: और फिर "mkdir -p" कम से कम ऊपर पोस्ट किए गए कोड के समान ही करेगा!
ypnos

7
इस कोड में एक सूक्ष्म दौड़ की स्थिति है जिसे मैं वास्तव में हिट करता हूं। यह केवल तब होता है जब कई प्रोग्राम एक साथ शुरू होते हैं और एक ही फ़ोल्डर पथ बनाते हैं। फिक्स if (errno != EEXIST) { status = -1; }जब mkdir विफल रहता है जोड़ने के लिए है।
स्विच करें

2
@ शिट: धन्यवाद। stat()इससे पहले उपयोग के साथ परेशानी है mkdir(); यह एक TOCTOU (चेक का समय, उपयोग का समय) समस्या है। मैंने बग को एक शेल स्क्रिप्ट के साथ गुदगुदाने की कोशिश की, जिसमें पृष्ठभूमि में 13 प्रक्रियाएं चल रही थीं, वही 29-तत्व पथ बना रहा था, और इसे हिट करने का प्रबंधन नहीं किया। फिर मैंने 20 बार कांटा करने के लिए परीक्षण कार्यक्रम को हैक किया और प्रत्येक बच्चे की कोशिश की, और वह बग को हिट करने में कामयाब रहा। तय कोड होगा if (mkdir(path, mode) != 0 && errno != EEXIST) status = -1;। यह बग नहीं दिखाता है।
जोनाथन लेफलर

2
@DavidMerinos: वे हेडर हैं ( jlss.h, emalloc.h), लाइब्रेरीज़ नहीं। हालांकि, कोड मेरे में उपलब्ध है SOQ भंडार GitHub पर फ़ाइलों के रूप में (स्टैक ओवरफ़्लो प्रश्न) jlss.h, emalloc.cऔर emalloc.hमें src / libsoq उप-निर्देशिका। आप की आवश्यकता होगी posixver.hभी, और कुछ अन्य लोगों ( debug.h, stderr.c, stderr.h- मुझे लगता है कि यह है, लेकिन क्या आप सभी कि निर्देशिका में होना चाहिए आवश्यकता है)।
जोनाथन लेफ़लर

157

Boost.Filesystem के साथ आसान: create_directories

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

रिटर्न: trueयदि एक नई निर्देशिका बनाई गई थी, अन्यथा false


9
ठीक है, अधिकांश बूस्ट लाइब्रेरी हेडर-ओनली हैं, जिसका अर्थ है कि आपके द्वारा उपयोग किए जाने के अलावा कोई ओवरहेड नहीं है। Boost.Filesystem के मामले में, इसे संकलन की आवश्यकता है। मेरी डिस्क पर, संकलित पुस्तकालय का वजन ~ 60KB है।
बेनोइट

1
@ लिपिस: कृपया सटीक अपने एम्बेडेड सिस्टम क्या है। मेरा मानना ​​है कि यह बहुत अधिक हर लिनक्स वितरण पर उपलब्ध होना चाहिए।
बेनोइट

4
सी ++ 11 compilers @danijar ने उल्लेख किया पर के बारे में, टिप्पणी यहाँ : यह स्पष्ट कर दिया 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
बढ़ावा देना :: filesystem केवल हेडर नहीं है: stackoverflow.com/questions/13604090/…
ftvs

2
IMHO: मेरी किसी भी परियोजना में, जो कुछ महत्वपूर्ण करने और समय की कसौटी पर खरा उतरने के लिए है, यह अविश्वसनीय रूप से उपयोगी और शक्तिशाली मानकीकृत साधनों के एक सेट को बढ़ावा देने के लिए संकलन के लायक है। इसका एक टन पहले ही मानक C ++ में अपना रास्ता बना चुका है, निश्चित रूप से आने के लिए और अधिक के साथ। इसे आज़माएं, इसके साथ रहें, यदि आपके पास तुच्छ आवश्यकताओं से अधिक है और आप पहिया को सुदृढ़ नहीं करना चाहते हैं तो आपको लाभ होगा। :-)
मूडबुक

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

सबसे छोटा तरीका है जो मैं सोच सकता हूं (कोड की लंबाई के संदर्भ में, जरूरी नहीं कि निष्पादन समय)।

यह क्रॉस-प्लेटफ़ॉर्म नहीं है, लेकिन लिनक्स के तहत काम करेगा।


1
यदि आप एक शेल कमांड के रूप में समाधान देने जा रहे हैं, तो सिस्टम (3)
dmckee --- पूर्व-संचालक बिल्ली का बच्चा

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 इरानो को अनदेखा करें।


मजेदार तथ्य: कम से कम सोलारिस और एचपी / यूएक्स में एमकेडीआरपी () है, हालांकि यह पोर्टेबिलिटी के लिए स्पष्ट रूप से इष्टतम नहीं है।
मार्टिन कारपेंटर

यह बात है .. कि मैं इन सभी कार्यों को अलग से नहीं बुलाना चाहता।
लिपिस

Mkdir को कॉल करना कुछ समय का तरीका होगा, एक बार कॉलिंग सिस्टम की तुलना में तेज़ी से।
पॉल टॉम्बलिन

मुझे समझ नहीं आ रहा है कि आप क्या सुझाव दे रहे हैं: अलग-अलग तर्कों के साथ 4 बार एमकेडीआर कॉल करना? ("/tmp/",...), ("/tmp/a/",...), ("/tmp/a/b/",...),("/tmp/a/b/c/",...)
एंटोनियो

1
फिर, यह तीन बार एक ही कॉल करने के लिए बहुत तुच्छ है। बिंदु लोगों को पर्याप्त जानकारी देने के लिए है कि वे कोड लिख सकते हैं, न कि उनके लिए कोड लिखने के लिए।
पॉल टॉम्बलिन

25

यहाँ कोड का मेरा उदाहरण है (यह विंडोज और लिनक्स दोनों के लिए काम करता है):

#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

मैं दूसरी उस टिप्पणी! यह (आश्चर्यजनक रूप से) एक निर्देशिका बनाने के लिए एक पोर्टेबल सी ++ तरीका खोजने के लिए एक तुच्छ कार्य नहीं है। इस उत्तर को और अधिक बढ़ाने की जरूरत है।
मैनुअल लफोंड

1
Windows के अंतर्गत, isDirExist काम नहीं करता है यदि अनुगामी चरित्र एक बैकस्लैश है। हमेशा झूठा लौटता है। मुझे कोड को संशोधित करना है: std :: string dirPath (पथ); जबकि ('\\' == * dirPath.rbegin ()) dirPath.pop_back (); ... और फिर, _stat को कॉल में dirPath.c_str () पास करें।
मिल्लोकडीपी

Windows API में प्री- कंपाइलर टेस्ट के लिए "गैर-एएनएसआई नाम संगतता के लिए" stat(संबंधित __STDC__) की आवश्यकता नहीं है।
सैंडबर्ग

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" की आवश्यकता होती है। और LDLIBS को "-lstdc ++ fs"। बाद के संभावित भविष्य में इसकी आवश्यकता नहीं होगी।


नए पर्याप्त विज़ुअल C ++ और "/ std: c ++ नवीनतम" के साथ भी काम करना चाहिए। देखें: blogs.msdn.microsoft.com/vcblog/2018/05/07/… और developercommunity.visualstudio.com/content/problem/296680/…
Ron Burk

9

यह पिछले की तरह ही है लेकिन पीछे की ओर पीछे की तरफ स्ट्रिंग के माध्यम से आगे काम करता है। अंतिम विफलता के लिए सही मान के साथ गलत है। यदि एक प्रमुख स्लैश है, तो लूप के माध्यम से एक अतिरिक्त समय है जिसे लूप के बाहर एक 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';

}

7

आपने कहा "C ++" लेकिन यहाँ हर कोई "बैश शेल" सोच रहा है।

ग्नू को स्रोत कोड देखें mkdir; फिर आप देख सकते हैं कि C ++ में शेल कमांड को कैसे लागू किया जाए।


अच्छी तरह से सिस्टम ("mkdir ...") लिनक्स पर चाल करना चाहिए। हालांकि यह क्रॉस-प्लेटफॉर्म नहीं है।
क्रिस्टोफ़े डी

मैं दूसरी बात करता हूं जो @MartinCarpenter कहती है
जोशुआ हेजेज

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

यह मेरे लिए सबसे अच्छा समाधान है! धन्यवाद!)))
नव

शायद यह एक डंप सवाल है, लेकिन mkdir से पहले "::" उपसर्ग क्या है?
रेई रोडेड

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

यदि आपको कास्ट कास्टिंग पसंद नहीं है और अस्थायी रूप से स्ट्रिंग को संशोधित करना है, तो बस एक करें strdup()और free()इसे बाद में करें।


एक gist को भी पोस्ट किया है, इसलिए मैं यह नहीं भूलता कि मैंने इसे अगली बार कहाँ रखा है :) gist.github.com/jonasfj/7797272
jonasfj

2
यह एक स्ट्रिंग को संशोधित करने की कोशिश करने के लिए बुराई है जिसे एक स्थिर के रूप में पारित किया जाता है। इसके अलावा अन्य सभी, यह नाटकीय विफलताओं के लिए नेतृत्व करने की संभावना है अगर इसे कभी भी एक स्ट्रिंग शाब्दिक रूप से पारित किया जाता है।
जोनाथन लेफ्लर

2
बिल्कुल सही .... यह वास्तव में बुरा है ... शायद यह बेहतर होगा ...
jonasfj

3

चूंकि यह पोस्ट "क्रिएट डायरेक्ट्री ट्री" के लिए Google में उच्च स्थान पर है, इसलिए मैं एक उत्तर पोस्ट करने जा रहा हूं जो विंडोज के लिए काम करेगा - यह UNICODE या MBCS के लिए संकलित Win32 API का उपयोग करके काम करेगा। यह ऊपर मार्क के कोड से पोर्ट किया गया है।

चूंकि यह विंडोज है जिसके साथ हम काम कर रहे हैं, निर्देशिका विभाजक बैक-स्लैश हैं, फॉरवर्ड स्लैश नहीं। यदि आप आगे की ओर स्लैश रखते हैं, तो बदल '\\'दें'/'

इसके साथ काम करेंगे:

c:\foo\bar\hello\world

तथा

c:\foo\bar\hellp\world\

(अर्थात: ट्रैश स्लैश की आवश्यकता नहीं है, इसलिए आपको इसके लिए जांच करने की आवश्यकता नहीं है।)

"बस विंडोज में SHCreateDirectoryEx () का उपयोग करें" कहने से पहले , ध्यान दें कि SHCreateDirectoryEx () वंचित है और विंडोज के भविष्य के संस्करणों से किसी भी समय हटाया जा सकता है।

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

एक छोटा सा mod - अगर पथ backslashes होता है यह काम नहीं करता है। यहाँ: `LPCTSTR szLast = _tcsrchr (szPathTree, '\\');` आपको बस इसे जोड़ने की आवश्यकता है: `` if (nullptr == szLast) / SzLast = _tcsrchr (szPathTree, '/'); } `` `
डेन-जैसन

1
जानकारी के लिए धन्यवाद। अगर कोई रास्ता मिला हुआ हो तो क्या होगा? यानी: c:\this\is\a/mixed/path\of\slashesआमतौर पर विंडोज स्लैश बैकस्लैश होते हैं। क्या होना चाहिए कॉल करने वाले को पथ को साफ करना चाहिए और यह सुनिश्चित करना चाहिए कि इस पद्धति को कॉल करने से पहले सभी स्लैश उचित हैं।
एंडी

3

मुझे पता है कि यह एक पुराना प्रश्न है, लेकिन यह Google खोज परिणामों पर उच्च दिखाता है और यहां दिए गए उत्तर वास्तव में C ++ में नहीं हैं या थोड़ा बहुत जटिल हैं।

कृपया ध्यान दें कि मेरे उदाहरण में createDirTree () बहुत ही सरल है क्योंकि सभी हेवी लिफ्टिंग (एरर चेकिंग, पाथ वेरीगेशन) को क्रिएट डायर () द्वारा किया जाना है। अगर डायरेक्टरी पहले से मौजूद है या पूरी चीज काम नहीं करेगी, तो भी createDir () सही होना चाहिए।

यहाँ मैं 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

यहाँ कई दृष्टिकोणों का वर्णन किया गया है, लेकिन उनमें से अधिकांश को आपके कोड में आपके पथ की हार्ड कोडिंग की आवश्यकता है। QDir और QFileInfo, 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

यहां C / C ++ पुनरावर्ती फ़ंक्शन है जो dirname()निर्देशिका ट्री के नीचे-ऊपर ट्रैवर्स का उपयोग करता है । जैसे ही यह मौजूदा पूर्वजों को ढूंढेगा, यह रुक जाएगा।

#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विकल्प का अर्थ है "आवश्यक रूप से मूल निर्देशिका बनाना"।


पॉल के जवाब को देखने के बाद, मुझे एहसास हुआ कि मैंने (और बहुत से अन्य लोगों ने) इस सवाल को गलत समझा ...
rmeador

अगर कोई इसे सिस्टम में बदलकर इसे अपडेट कर सकता है ("mkdir -p / tmp / a / {b, c} / d"), क्योंकि प्रश्न इसे शेल में करने के बारे में नहीं है .. लेकिन C ++ के माध्यम से।
लिपिस

मुझे लगता है कि {a, b} श-व्युत्पन्न और csh- व्युत्पन्न दोनों गोले में काम करेंगे। मुझे यकीन नहीं है कि यह एक सिस्टम () कमांड में काम करेगा, हालांकि।
पॉल टॉम्बलिन

1
@ लिपिस: ओपी के प्रश्न के लिए सिस्टम () के माध्यम से ऐसा करना एक अच्छा समाधान नहीं है। @Andy: मैंने पहले कभी इस पर विचार नहीं किया, लेकिन मैंने इसे "गूंज" के साथ "mddir -p" की जगह पर परीक्षण किया और यह प्रिंट करता है "/ tmp / a / b / d / tmp / a / c / d" जो यह बताता है कि यह ऐसा करना है, mkdir नहीं।
rmeador

@rmeador: यदि यह एक अच्छा समाधान नहीं है, तो क्या आपके पास सुझाव देने के लिए कुछ और है? मैं सी ++ के माध्यम से ऐसा करना चाहता हूं ... यह मेरा मुद्दा नहीं है कि शेल के माध्यम से कैसे किया जाए ..
लिपिस
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.