আমি কীভাবে সি ++ / লিনাক্সে ডিরেক্টরি ট্রি তৈরি করতে পারি?


109

আমি সি ++ / লিনাক্সে একাধিক ডিরেক্টরি তৈরির সহজ উপায় চাই।

উদাহরণস্বরূপ আমি ডিরেক্টরিতে একটি ফাইল lola.file সংরক্ষণ করতে চাই:

/tmp/a/b/c

তবে ডিরেক্টরিগুলি না থাকলে আমি সেগুলি স্বয়ংক্রিয়ভাবে তৈরি করা চাই। একটি কাজের উদাহরণ নিখুঁত হবে।


সি ++ এর জন্য প্রতি সেয়ে ডিরেক্টরি এবং গাছ তৈরি করার জন্য কোনও অন্তর্নির্মিত সুবিধা নেই । আপনাকে সি এবং সিস্টেম কল বা বুস্টের মতো একটি বাহ্যিক গ্রন্থাগার ব্যবহার করতে হবে। সি এবং সিস্টেম কলগুলি প্ল্যাটফর্ম নির্ভর।
jww 20'14

6
@ নোলোডার অনেক লোককে ধন্যবাদ জানায় .. তবে আমি মনে করি 4 বছর পরে আমার উত্তরটি পেয়েছি কারণ আপনি 13 টি বিভিন্ন উপায়ে বেলো দেখতে পাচ্ছেন ...
লিপিস

হ্যাঁ, আমি অবাক হয়েছিলাম কেউই স্পষ্টভাবে বলেনি যে আপনি এটি সি ++ এ করতে পারবেন না (ধরে নেওয়া যে আপনি লিনাক্সে কাজ করে এমন সি ++ তে পোর্টেবল পদ্ধতিটি চেয়েছিলেন)। তবে আপনি সম্ভবত এটি জানতেন;)। নন-পোর্টেবল সি কোডের জন্য প্রচুর ভাল পরামর্শ ছিল।
jww 20'14

"সি ++ / লিনাক্স" কী?
লাইটনেস রেস

3
@ লাইটনেসেসেসিনআরবিট এটি লিনাক্সে সি ++ তে আমার বিশ্ববিদ্যালয়ের বছরগুলি :)
লিপিস

উত্তর:


59

সি ++ 17 বা তার পরে, <filesystem>ফাংশন সহ স্ট্যান্ডার্ড শিরোনাম রয়েছে std::filesystem::create_directories যা আধুনিক সি ++ প্রোগ্রামগুলিতে ব্যবহার করা উচিত। যদিও C ++ স্ট্যান্ডার্ড ফাংশনগুলির মধ্যে POSIX- নির্দিষ্ট স্পষ্টত অনুমতি (মোড) যুক্তি নেই।

তবে, এখানে একটি সি ফাংশন যা সি ++ সংকলকগুলির সাথে সংকলিত হতে পারে।

/*
@(#)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 ইন্টেল কোর আই 7, ম্যাক ওএস এক্স 10.7.4 চলমান) তে সমস্যাটি পুনর্বিবেচনা এবং পুনরুত্পাদন করা হয়েছে এবং পরামর্শ দেয় যে সমস্যাটি পুনর্বিবেচনায় স্থির করা হয়েছে (তবে পরীক্ষার ফলে কেবল বাগের উপস্থিতি দেখাতে পারে , কখনও তাদের অনুপস্থিতি)। প্রদর্শিত কোডটি এখন v1.16; v1.13 সাল থেকে কসমেটিক বা প্রশাসনিক পরিবর্তন হয়েছে (যেমন mkpath.hপরিবর্তে ব্যবহার হিসাবে jlss.hএবং <unistd.h>কেবলমাত্র পরীক্ষার কোডে নিঃশর্তভাবে অন্তর্ভুক্ত )। এটি যুক্তিযুক্ত যুক্তিসঙ্গত যেটি যদি আপনার অস্বাভাবিকভাবে পুনরুদ্ধারের ব্যবস্থা না "sysstat.h"করে <sys/stat.h>তবে এটি দ্বারা প্রতিস্থাপন করা উচিত ।

(আপনাকে এট্রিবিউশন সহ যে কোনও উদ্দেশ্যে এই কোডটি ব্যবহার করার অনুমতি দেওয়া হয়েছে))

এই কোডটি গিটহাবের আমার এসওকিউ (স্ট্যাক ওভারফ্লো প্রশ্নগুলি) সংগ্রহস্থলগুলিতে ফাইল হিসাবে mkpath.cএবং এসসিআর / so-0067-5039 উপ-ডিরেক্টরিতে mkpath.h(ইত্যাদি) উপলভ্য


2
এটি অবশ্যই সিস্টেমের চেয়ে দ্রুত is সিস্টেমের সাথে প্রচুর ওভারহেড জড়িত। মূলত, প্রক্রিয়াটি কাঁটাচামচ করতে হবে, তারপরে কমপক্ষে দুটি বাইনারি লোড করতে হবে (একটি সম্ভবত ইতিমধ্যে ক্যাশে থাকবে), যার উপর অন্যটির আরও একটি কাঁটাচামচ থাকবে, ...
ypnos

1
আমি ভুলে গিয়েছিলাম: এবং তারপরে "mkdir -p" কমপক্ষে উপরে পোস্ট করা কোডের মতোই করবে!
ypnos

7
এই কোডটিতে একটি সূক্ষ্ম রেসের শর্ত রয়েছে যা আমি আসলে আঘাত করেছি। এটি তখনই ঘটে যখন একাধিক প্রোগ্রাম একসাথে শুরু হয় এবং একই ফোল্ডারটির পথ তৈরি করে। ফিক্স যোগ হয় if (errno != EEXIST) { status = -1; }যখন mkdir, ব্যর্থ।
স্যুইচ করুন

2
@ সুইচ: ধন্যবাদ stat()আগে ব্যবহারে এটাই সমস্যা mkdir(); এটি একটি টেকটিউ (চেকের সময়, ব্যবহারের সময়) সমস্যা। আমি একই 29-এলিমেন্ট পাথ তৈরি করতে ব্যাকগ্রাউন্ডে 13 টি প্রক্রিয়া চালিত শেল স্ক্রিপ্টের সাথে বাগটি টিকল করার চেষ্টা করেছি, এবং এটি আঘাত করতে পরিচালনা করি না। তারপরে আমি পরীক্ষার প্রোগ্রামটি কাঁটাচামচ করতে 20 বার হ্যাক করেছি এবং প্রতিটি বাচ্চাকে চেষ্টা করার চেষ্টা করেছি এবং এটি বাগটিতে আঘাত করতে সক্ষম হয়েছিল। ফিক্সড কোড থাকবে if (mkdir(path, mode) != 0 && errno != EEXIST) status = -1;। এটি বাগ প্রদর্শন করে না।
জোনাথন লেফলার

2
@ ডেভিডমারিনোস: তারা গ্রন্থাগার নয় jlss.h, শিরোনাম ( , emalloc.h)। তবে, কোড আমার পাওয়া যায় SOQ সংগ্রহস্থলের GitHub থেকে ফাইল হিসেবে (স্ট্যাক ওভারফ্লো প্রশ্নাবলি) jlss.h, emalloc.cএবং emalloc.hমধ্যে src / libsoq উপ-নির্দেশিকা। আপনি প্রয়োজন হবে posixver.hখুব, এবং অন্য কয়েকজন ( debug.h, stderr.c, stderr.h- আমি মনে করে যে এটি, কিন্তু তুমি কি সব যে ডিরেক্টরির মধ্যে হওয়া উচিত প্রয়োজন)।
জোনাথন লেফলার

157

বুস্ট.ফায়ার সিস্টেমের সাহায্যে সহজ: create_directories

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

রিটার্নস: trueযদি কোনও নতুন ডিরেক্টরি তৈরি করা হয়, অন্যথায় false


9
ভাল, বেশিরভাগ বুস্ট লাইব্রেরিগুলি কেবলমাত্র শিরোনামযুক্ত, যার অর্থ আপনি যা ব্যবহার করেন তা ছাড়া কোনও ওভারহেড নেই। বুস্ট.ফাইলেস্টেমের ক্ষেত্রে এটির জন্য যদিও সংকলন প্রয়োজন। আমার ডিস্কে, সংকলিত লাইব্রেরির ওজন। 60KB।
বেনোয়েট

1
@ লিপিস: আপনার এমবেডেড সিস্টেমটি কী তা দয়া করে নিশ্চিত করুন। আমি বিশ্বাস করি এটি প্রতিটি লিনাক্স বিতরণে পাওয়া উচিত।
বেনোয়েট

4
সি ++ 11 কম্পাইলার @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
বুস্ট :: ফাইলসিস্টেম শুধুমাত্র হেডার-নয়: stackoverflow.com/questions/13604090/...
ftvs

2
আইএমএইচও: আমার যে কোনও প্রকল্পে যা উল্লেখযোগ্য কিছু করার এবং সময়ের পরীক্ষা দাঁড়ানোর উদ্দেশ্যে বোঝানো হয়, এটি এমন একটি সংকলন মূল্যবান যে এটি অবিশ্বাস্যরূপে কার্যকর এবং শক্তিশালী মানক সরঞ্জামগুলির উত্স হিসাবে উত্সাহিত করতে পারে। এর এক টন ইতিমধ্যে আরও অনেক কিছু দিয়ে স্ট্যান্ডার্ড সি ++ এ প্রবেশ করেছে। এটি চেষ্টা করে দেখুন, এটির সাথে আটকে দিন, আপনার যদি তুচ্ছ প্রয়োজনের চেয়ে বেশি থাকে এবং আপনি চাকাটি পুনরায় উদ্ভাবন করতে না চান তবে আপনি উপকৃত হবেন। :-)
মুডবুম

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

আমি ভাবতে পারি সবচেয়ে সংক্ষিপ্ততম উপায় (কোডের দৈর্ঘ্যের দিক থেকে, কার্যকরভাবে কার্যকর করার সময় নয়)।

এটি ক্রস প্ল্যাটফর্ম নয় তবে লিনাক্সের আওতায় কাজ করবে।


1
যদি আপনি শেল কমান্ড হিসাবে সমাধানটি দিতে যাচ্ছেন তবে সিস্টেম (3)
ডিএমকেকে --- প্রাক্তন মডারেটর বিড়ালছানা

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

থেকে এখানে । সি এপি-তে -p পতাকার সমতুল্য না থাকায় আপনাকে / tmp, / tmp / a, / tmp / a / b / এবং তারপরে / tmp / a / b / c এর জন্য পৃথক mkdirs করতে হতে পারে। আপনি যখন উচ্চ স্তরের কাজটি করছেন তখন নিশ্চিত হন এবং EEXISS এর ভুলটি উপেক্ষা করুন।


মজাদার ঘটনা: কমপক্ষে সোলারিস এবং এইচপি / ইউএক্সের এমকিডির্প () রয়েছে, যদিও এটি স্পষ্টতই বহনযোগ্যতার পক্ষে অনুকূল নয়।
মার্টিন কার্পেন্টার

এটাই কথা .. যে আমি এই সমস্ত ফাংশনকে আলাদাভাবে কল করতে চাই না।
লিপিস

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
উইন্ডোজের অধীনে, পিছনের অক্ষর ব্যাকস্ল্যাশ হলে isDirExist কাজ করে না। সর্বদা মিথ্যা প্রত্যাবর্তন। আমাকে কোডটি সংশোধন করতে হবে: std :: স্ট্রিং ডিরপথ (পথ); যখন ('\\' == * dirPath.rbegin ()) dirPath.pop_back (); ... এবং তারপরে অবশ্যই _ স্ট্যাট-এ কল করে dirPath.c_str () পাস করুন।
মিলোডিসি

উইন্ডোজ এপিআই- এ প্রাকম্পম্পাইলার পরীক্ষার প্রয়োজন নেই stat(সম্পর্কিত __STDC__) "সামঞ্জস্যের জন্য নন-এএনএসআই নাম রয়েছে" ।
সানডবার্গ

18

এটি লক্ষ করা উচিত যে সি ++ 17 ফাইল সিস্টেম ইন্টারফেস থেকে শুরু করা স্ট্যান্ডার্ড লাইব্রেরির অংশ। এর অর্থ হ'ল ডিরেক্টরি তৈরি করতে কারও কাছে নিম্নলিখিত থাকতে পারে:

#include <filesystem>

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

এখানে আরও তথ্য: https://en.cppreferences.com/w/cpp/filesystem/create_directory

অতিরিক্তভাবে, জিসিসি সহ, সিএফএলজিএসে একজনকে "-std = c ++ 17" দরকার। এবং "-lstdc ++ fs" এলডিআইবিএস-এ। পরবর্তী সম্ভাব্য ভবিষ্যতে প্রয়োজন হবে না।


নতুন পর্যাপ্ত ভিজ্যুয়াল সি ++ এবং "/ স্টাডি: সি ++ সর্বশেষ" এর সাথেও কাজ করা উচিত। দেখুন: ব্লগস.এমএসএনএন.মাইক্রোসফট. / ভিসাব্লগ / 2018 / 05 / 07/… এবং বিকাশকারমমিউটি.ভিজুয়ালস্টুডিও
রন বার্ক

9

এটি আগের মতই তবে পুনরাবৃত্তির পিছনে পিছনে স্ট্রিংয়ের মাধ্যমে এগিয়ে কাজ করে। শেষ ব্যর্থতার জন্য সঠিক মান দিয়ে ভুল করে। যদি শীর্ষস্থানীয় স্ল্যাশ থাকে তবে লুপের বাইরে অতিরিক্ত সময় থাকতে পারে যা লুপের বাইরের একটি ফাইন্ড_ফর্স্ট_ফ () এর মাধ্যমে বা অগ্রণী / এবং প্রাক সেট 1 নির্ধারণের মাধ্যমে এড়ানো যেত The দক্ষতা একই হয় আমরা কোনও দ্বারা সেট আপ হয়ে যাই কিনা প্রাক লুপ কলটি ব্যবহার করার সময় প্রথম লুপ বা প্রাক লুপ কল এবং জটিলতাটি কিছুটা বেশি (সামান্য) বেশি হবে।

#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

আপনি "সি ++" বলেছেন তবে এখানকার প্রত্যেকে "বাশ শেল" ভাবছেন বলে মনে হচ্ছে।

Gnu- তে সোর্স কোডটি দেখুন mkdir; তারপরে আপনি দেখতে পারবেন কীভাবে সি ++ এ শেল কমান্ডগুলি প্রয়োগ করা যায়।


ওয়েল সিস্টেম ("এমকেডির ...") লিনাক্সের উপর কৌশলটি করা উচিত। যদিও এটি ক্রস প্ল্যাটফর্ম নয়।
ক্রিস্টোফিড

@ মার্টিন কার্পেন্টার যা বলেছে তার পরে আমি দ্বিতীয়
জোশুয়া হেজেস

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

এটা আমার জন্য সেরা সমাধান! আপনাকে ধন্যবাদ!)))
নব্য

হতে পারে এটি একটি ডাম্প প্রশ্ন, তবে এমকিডিরের আগে "::" উপসর্গটি কী?
রায়

1
উত্তরটি খুঁজে
পেল

4

সুতরাং আমার mkdirp()আজকের দরকার , এবং এই পৃষ্ঠায় সমাধানগুলি অতি জটিল found অতএব আমি একটি মোটামুটি ছোট স্নিপেট লিখেছি, যা সহজেই অন্যদের জন্য অনুলিপি করা যায় যারা এই থ্রেডটিতে হোঁচট খায় তারা আশ্চর্য হয় যে কেন আমাদের এত লাইন কোডের প্রয়োজন।

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()এটি পরে করুন।


একটি টুকরোতেও পোস্ট করা হয়েছে, তাই আমি এটি ভুলে যাব না যে আমি এটির পরের বার এটির দরকারের
জায়গায়

2
ধ্রুবক হিসাবে পাস করা একটি স্ট্রিং সংশোধন করার চেষ্টা করা খারাপ। অন্য সব বাদে, এটি যদি কখনও স্ট্রিং আক্ষরিক অর্থে পাস করা হয় তবে এটি নাটকীয় ব্যর্থতার দিকে পরিচালিত করে।
জোনাথন লেফলার

2
পুরোপুরি ঠিক বলেছেন .... এটি আসলে খারাপ ... সম্ভবত
স্ট্রাইকপি

3

যেহেতু এই পোস্টটি "ডিরেক্টরী ট্রি ট্রি তৈরি করুন" এর জন্য গুগলে উচ্চ স্থান অর্জন করছে, তাই আমি একটি উত্তর পোস্ট করতে যাচ্ছি যা উইন্ডোজের পক্ষে কাজ করবে - এটি ইউনিকোডি বা এমবিসিএসের জন্য সংকলিত উইন 32 এপিআই ব্যবহার করে কাজ করবে। এটি উপরের মার্কের কোড থেকে পোর্ট করা আছে।

যেহেতু এটি উইন্ডোজ যার সাথে আমরা কাজ করছি, ডিরেক্টরি বিভাজকগুলি হ'ল ব্যাক-স্ল্যাশ, ফরোয়ার্ড স্ল্যাশ নয়। আপনি যদি না বরং ফরোয়ার্ড স্ল্যাশ করতে চান তবে পরিবর্তন '\\'করুন'/'

এটি এর সাথে কাজ করবে:

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

একটি সামান্য মোড - যদি पथটিতে ব্যাকস্ল্যাশ থাকে তবে এটি কাজ করে না। এখানে: P এলপিসিটিএসটিআরজলস্ট = _tcsrchr (szPathTree, '\\'); `আপনাকে কেবল এটি যুক্ত করতে হবে: n` `if (নালপ্ট্র == szLast) {szLast = _tcsrchr (szPathTree, '/'); `` ``
ডেন-জেসন

1
তথ্যের জন্য ধন্যবাদ। কোনও পথ মিশ্রিত হলে কী হবে? যেমন: c:\this\is\a/mixed/path\of\slashesসাধারণত উইন্ডোজ স্ল্যাশগুলি ব্যাকস্ল্যাশ হয়। যা হওয়া উচিত তা হ'ল কলারের পথটি স্যানিটাইজ করা উচিত এবং নিশ্চিত করা উচিত যে এই পদ্ধতিটি কল করার আগে সমস্ত স্ল্যাশগুলি যথাযথ।
অ্যান্ডি

3

আমি জানি এটি একটি পুরানো প্রশ্ন তবে এটি গুগল অনুসন্ধানের ফলাফলগুলিতে উচ্চ দেখায় এবং এখানে প্রদত্ত উত্তরগুলি সত্যিই সি ++ এ নয় বা কিছুটা জটিলও।

দয়া করে নোট করুন যে আমার উদাহরণে createDirTree () খুব সহজ কারণ সমস্ত ভারী উত্তোলন (ত্রুটি পরীক্ষা করা, পাথের বৈধতা) যেভাবেই হোক createDir () দ্বারা করা দরকার। ডিরেক্টরী ইতিমধ্যে উপস্থিত থাকলে বা পুরো জিনিসটি কাজ না করে তবে createDir () এর সত্য হওয়া উচিত।

আমি এখানে সি ++ তে কীভাবে করব:

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

অবশ্যই ক্রিয়েডির () ফাংশনটি সিস্টেম-নির্দিষ্ট হবে এবং অন্যান্য উত্তরগুলিতে এটি ইতিমধ্যে লিনাক্সের জন্য কীভাবে লিখতে হবে তার যথেষ্ট উদাহরণ রয়েছে, তাই আমি এড়িয়ে যাওয়ার সিদ্ধান্ত নিয়েছি।


1

যদি ডিয়ারের অস্তিত্ব না থাকে তবে এটি তৈরি করুন:

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

1

এখানে অনেকগুলি পদ্ধতির বর্ণনা দেওয়া হয়েছে তবে তাদের বেশিরভাগেরই আপনার কোডটিতে আপনার পথের কঠোর কোডিং দরকার। এই সমস্যার জন্য একটি সহজ সমাধান রয়েছে, কিউডিআর এবং কিফিলআইএনফো, দুটি শ্রেণির কিউটি ফ্রেমওয়ার্ক ব্যবহার করে। আপনার ইতিমধ্যে লিনাক্স পরিবেশে Qt ব্যবহার করা সহজ হওয়া উচিত।

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

নিশ্চিত হয়ে নিন যে সেই পথে আপনার লেখার অ্যাক্সেস রয়েছে।



0

এখানে সি / সি ++ রিকर्सিভ ফাংশন যা 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বিকল্পটির অর্থ "প্রয়োজনীয় হিসাবে পিতামাত ডিরেক্টরিগুলি তৈরি করা"।


পলের উত্তরটি দেখার পরে, আমি বুঝতে পারি যে আমি (এবং আরও অনেক লোক) প্রশ্নটি ভুল
বুঝেছি

কেউ যদি কেবলমাত্র এটি সিস্টেমে পরিবর্তন করে আপডেট করতে পারেন ("এমকিডির -পি / টিএমপি / এ / {বি, সি} / ডি"), কারণ শেলগুলি না করে প্রশ্নগুলি তৈরি করছে .. তবে সি ++ এর মাধ্যমে।
লিপিস

আমি মনে করি {a, b sh উভয় sh- প্রাপ্ত এবং csh- উদ্ভূত শেলগুলিতে কাজ করবে। যদিও এটি কোনও সিস্টেম () কমান্ডে কাজ করবে কিনা তা আমি নিশ্চিত নই।
পল টমব্লিন

1
@ লিপিস: সিস্টেমের মাধ্যমে এটি করা () ওপি-র প্রশ্নের ভাল সমাধান নয়। @ অ্যান্ডি: আমি এর আগে কখনও বিবেচনা করি নি, তবে আমি "এমকডিয়ার-পি" কে "প্রতিধ্বনি" দিয়ে প্রতিস্থাপন করে এটি পরীক্ষা করেছি "/ টিএমপি / এ / বি / ডি / টিএমপি / এ / সি / ডি", যা পরামর্শ দেয় এটি শেল এটি করছে, এমকেডির নয়।
rmeador

@ আরমিডোর: যদি এটি ভাল সমাধান না হয় তবে আপনার কাছে প্রস্তাব দেওয়ার মতো আরও কিছু আছে? আমি এটি সি ++ এর মাধ্যমে করতে চাই ... এটি আমার সমস্যা শেলের মাধ্যমে কীভাবে করা যায় তা নয় ...
লিপিস
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.