C ++ / Linux'ta nasıl dizin ağacı oluşturabilirim?


109

C ++ / Linux'ta birden çok dizin oluşturmanın kolay bir yolunu istiyorum.

Örneğin lola.file dosyasını dizine kaydetmek istiyorum:

/tmp/a/b/c

ancak dizinler yoksa otomatik olarak oluşturulmalarını istiyorum. Çalışan bir örnek mükemmel olur.


C ++, kendi başına dizin ve ağaç oluşturmak için yerleşik olanaklara sahip değildir . C ve sistem çağrılarını veya Boost gibi harici bir kitaplığı kullanmanız gerekecektir. C ve sistem çağrıları platforma bağlı olacaktır.
jww

6
@noloader Çok teşekkürler dostum .. ama sanırım 4 yıl sonra cevabımı 13 farklı şekilde görebileceğiniz gibi aldım ...
Lipis

Evet, kimsenin bunu C ++ 'da yapamayacağınızı açıkça belirtmemesine şaşırdım (Linux'ta çalışan C ++' da taşınabilir bir yöntem istediğinizi varsayarak). Ama muhtemelen bunu biliyordunuz;). Yine de taşınabilir olmayan C kodu için pek çok iyi öneri vardı.
jww

"C ++ / Linux" nedir?
Orbit'te Hafiflik Yarışları

3
@LightnessRacesinOrbit Linux'ta C ++ ile üniversite yıllarım :)
Lipis

Yanıtlar:


59

C ++ 17 veya üstü ile, modern C ++ programlarında kullanılması gereken <filesystem>işleve std::filesystem::create_directoriessahip standart bir başlık vardır . Bununla birlikte, C ++ standart işlevlerinin POSIX'e özgü açık izinler (mod) bağımsız değişkeni yoktur.

Ancak, burada C ++ derleyicileriyle derlenebilecek bir C işlevi bulunmaktadır.

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

Makrolar STRDUP()ve FREE(), strdup()ve ' free()de bildirilen emalloc.h(ve içinde uygulanan) emalloc.cve hata denetimi sürümleridir estrdup.c. "sysstat.h"Kırık sürümleri ile başlık fırsatlar <sys/stat.h> ve ile değiştirilebilir <sys/stat.h>Modern Unix sistemleri üzerinde (ama birçok konu 1990 yılında geri vardı). Ve "mkpath.h"ilan eder mkpath().

V1.12 (cevabın orijinal versiyonu) ve v1.13 (cevabın değiştirilmiş versiyonu) arasındaki değişiklik EEXISTin do_mkdir(). Bu gerekli olduğu için Switch tarafından belirtildi - teşekkürler, Switch. Test kodu yükseltildi ve sorunu bir MacBook Pro'da (2.3 GHz Intel Core i7, Mac OS X 10.7.4 çalıştıran) yeniden oluşturdu ve sorunun revizyonda düzeltildiğini gösteriyor (ancak testler yalnızca hataların varlığını gösterebilir , asla yoklukları). Gösterilen kod artık v1.16'dır; v1.13'ten bu yana yapılan kozmetik veya idari değişiklikler ( yalnızca test kodunun mkpath.hyerine jlss.hve <unistd.h>koşulsuz olarak dahil edilmesi gibi ). Alışılmadık şekilde inatçı bir sisteminiz yoksa "sysstat.h"bunun ile değiştirilmesi gerektiğini iddia etmek mantıklıdır <sys/stat.h>.

(Bu kodu atıfta bulunan herhangi bir amaç için kullanma izniniz bulunmaktadır.)

Bu kod, GitHub'daki SOQ (Stack Overflow Questions) depomda dosyalar olarak mkpath.cve mkpath.h(vb.) Src / so-0067-5039 alt dizininde mevcuttur.


2
Kesinlikle sistemden daha hızlıdır. Sistemin çok fazla ek yükü var. Temel olarak, sürecin çatallanması gerekir, ardından en az iki ikili
dosyanın

1
Unuttum: Ve sonra "mkdir -p" en azından yukarıda yayınlanan kodla aynı şeyi yapacaktır!
ypnos

7
Bu kodda gerçekten çarptığım ince bir yarış durumu var. Yalnızca birden çok program aynı anda başladığında ve aynı klasör yolunu oluşturduğunda olur. Düzeltme, if (errno != EEXIST) { status = -1; }mkdir başarısız olduğunda eklemektir .
Anahtarı

2
@Switch: Teşekkürler. Daha stat()önce kullanmanın sorunu budur mkdir(); bu bir TOCTOU (kontrol zamanı, kullanım zamanı) problemidir. Arka planda aynı 29 elemanlı yolu oluşturan 13 işlemi çalıştıran bir kabuk betiği ile hatayı gıdıklamayı denedim ve ona ulaşmayı başaramadım. Sonra test programını 20 kez çatallanmak ve her çocuğun denemesini sağlamak için hackledim ve bu hatayı çözmeyi başardı. Sabit kodda olacaktır if (mkdir(path, mode) != 0 && errno != EEXIST) status = -1;. Bu hatayı göstermiyor.
Jonathan Leffler

2
@DavidMerinos: bunlar kitaplıklar değil jlss.h, başlıklardır ( , emalloc.h). Ancak, kod benim mevcuttur SOQ dosyaları olarak GitHub'dan (yığın taşması Sorular) deposu jlss.h, emalloc.cve emalloc.hiçinde src / libsoq alt dizininde. Şunlar gerekir posixver.hde ve birkaç başka ( debug.h, stderr.c, stderr.h- Ne tüm bu dizinde olmalıdır gerekmez bu olduğunu düşünüyorum ama).
Jonathan Leffler

157

Boost.Filesystem ile Kolay: create_directories

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

İade: trueYeni bir dizin oluşturulmuşsa, aksi halde false.


9
Pek çok yükseltme kitaplığı yalnızca başlıklara yöneliktir, yani kullandığınızdan başka ek yük yoktur. Boost.Filesystem durumunda, yine de derleme gerektirir. Diskimde, derlenen kitaplık ~ 60KB ağırlığındadır.
Benoît

1
@Lipis: Lütfen gömülü sisteminizin ne olduğunu kesin olarak belirtin. Hemen hemen her linux dağıtımında mevcut olması gerektiğine inanıyorum.
Benoît

4
@Danijar bahsettiği C ++ 11 derleyiciler üzerinde ilgili olarak, açıklama burada : o açık hale 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 yalnızca başlık değildir: stackoverflow.com/questions/13604090/…
ftvs

2
IMHO: Önemli bir şey yapmak ve zamanın testine dayanmak isteyen herhangi bir projemde, destek gibi inanılmaz derecede kullanışlı ve güçlü standartlaştırılmış araçlara sahip olmak derlemeye değer. Bir tonu zaten standart C ++ 'ya girdi ve kesinlikle daha fazlası gelecek. Deneyin, sadık kalın, önemsiz ihtiyaçlardan daha fazlasına sahipseniz ve tekerleği yeniden icat etmek istemiyorsanız fayda sağlayacaksınız. :-)
moodboom

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

düşünebildiğim en kısa yol (kodun uzunluğu açısından, mutlaka yürütme süresi değil).

Çapraz platform değil ama Linux altında çalışacak.


1
Çözümü bir kabuk komutu olarak verecekseniz, system (3)
dmckee - eski moderatör kedicik

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

Gönderen burada . / Tmp, / tmp / a, / tmp / a / b / ve sonra / tmp / a / b / c için ayrı mkdir'ler yapmanız gerekebilir çünkü C api'de -p bayrağının bir eşdeğeri yoktur. Üst seviye olanları yaparken EEXISTS hatalarını göz ardı ettiğinizden emin olun.


Eğlenceli gerçek: En azından Solaris ve HP / UX'te mkdirp () vardır, ancak bu açıkça taşınabilirlik için ideal değildir.
Martin Carpenter

Bütün bu işlevleri ayrı ayrı adlandırmak istemediğim nokta da bu.
Lipis

Mkdir'i birkaç kez aramak, sistemi bir kez aramaktan çok daha hızlı olacaktır.
Paul Tomblin

Ne önerdiğinizi anlamıyorum: mkdir'i 4 kez farklı argümanlarla çağırmak? ("/tmp/",...), ("/tmp/a/",...), ("/tmp/a/b/",...),("/tmp/a/b/c/",...)
Antonio

1
Yine, aynı aramayı üç kez yapmak oldukça önemsiz. Önemli olan insanlara kodu yazabilecekleri kadar bilgi vermek, onlar için kod yazmamaktır.
Paul Tomblin

25

İşte kod örneğim (hem Windows hem de Linux için çalışıyor):

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

Kullanımı:

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

Ben bu yoruma katılıyorum! Bir dizin oluşturmak için taşınabilir bir C ++ yolu bulmak (şaşırtıcı bir şekilde) önemsiz bir görev değildir. Bu yanıtın daha fazla oylamaya ihtiyacı var.
Manuel Lafond

1
Windows altında, sondaki karakter bir ters eğik çizgi ise isDirExist çalışmaz. Her zaman yanlış döndürür. Kodu şu şekilde değiştirmem gerekiyor: std :: string dirPath (yol); while ('\\' == * dirPath.rbegin ()) dirPath.pop_back (); ... ve sonra, elbette, _stat çağrısında dirPath.c_str () 'yi iletin.
MiloDC

Windows API, için "Uyumluluk için ANSI olmayan adlara" sahiptir stat(ile ilgili__STDC__ ön derleyici testine gerek olmadığı ) .
Sandburg

18

C ++ 17 dosya sistemi arayüzünden başlamanın standart kitaplığın bir parçası olduğu unutulmamalıdır. Bu, dizinler oluşturmak için aşağıdakilere sahip olunabileceği anlamına gelir:

#include <filesystem>

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

Daha fazla bilgi burada: https://en.cppreference.com/w/cpp/filesystem/create_directory

Ek olarak, gcc ile CFLAGS için "-std = c ++ 17" gerekir. Ve LDLIBS'ye "-lstdc ++ fs". İkincisi, gelecekte potansiyel olarak gerekli olmayacak.


Ayrıca yeterince yeni Visual C ++ ve "/ std: c ++ latest" ile çalışmalıdır. Bakınız: blogs.msdn.microsoft.com/vcblog/2018/05/07/… ve developercommunity.visualstudio.com/content/problem/296680/…
Ron Burk

9

Bu, öncekine benzer, ancak yinelemeli olarak geriye gitmek yerine dizge boyunca ileriye doğru çalışır. Son başarısızlık için errno değerini doğru değerle bırakır. Başta bir eğik çizgi varsa, döngünün dışında bir find_first_of () aracılığıyla veya öndeki / ve ön ayarını 1 olarak belirleyerek önlenebilecek fazladan bir döngü vardır. Verimlilik, bir İlk döngü veya bir ön döngü çağrısı ve döngü öncesi çağrıyı kullanırken karmaşıklık (biraz) daha yüksek olacaktır.

#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 ++" dediniz ama buradaki herkes "Bash kabuğu" düşünüyor gibi görünüyor.

Gnu'nun kaynak kodunu kontrol edin mkdir; daha sonra kabuk komutlarını C ++ 'da nasıl uygulayacağınızı görebilirsiniz.


Well system ("mkdir ...") linux üzerinde hile yapmalı. Yine de çapraz platform değil.
ChristopheD

@MartinCarpenter'ın söylediği şeyi ikinciyim
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;
}

benim için en iyi çözüm! Teşekkür ederim!)))
neo

belki bu bir döküm sorusudur, ama mkdir'den önceki "::" öneki nedir?
Rayee Roded


4

Bu yüzden mkdirp()bugün ihtiyacım var ve bu sayfadaki çözümleri aşırı karmaşık buldum. Bu nedenle, bu konuya rastlayanlar için kolayca kopyalanabilen oldukça kısa bir pasaj yazdım, neden bu kadar çok satır koda ihtiyacımız olduğunu merak ediyorum.

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 çevrimini ve dizeyi geçici olarak değiştirmeyi sevmiyorsanız, sadece a strdup()ve free()sonra yapın.


Bir öze de gönderildi, bu yüzden bir dahaki sefere nereye koyacağımı unutmam :) gist.github.com/jonasfj/7797272
jonasfj

2
Sabit olarak geçirilen bir dizgeyi değiştirmeye çalışmak kötüdür. Her şey bir yana, eğer bir dizge birebir dizgiden geçirilirse dramatik hatalara yol açması muhtemeldir.
Jonathan Leffler

2
Kesinlikle doğru .... bu aslında kötü ... muhtemelen strcpy bunu daha iyi yapar ...
jonasfj

3

Bu gönderi "Dizin Ağacı Oluştur" için Google'da üst sıralarda yer aldığından, Windows için işe yarayacak bir yanıt göndereceğim - bu, UNICODE veya MBCS için derlenen Win32 API kullanılarak çalışacaktır. Bu, Mark'ın yukarıdaki kodundan alınmıştır.

Bu birlikte çalıştığımız Windows olduğundan, dizin ayırıcıları eğik çizgi değil, BACK-bölü işaretleridir. Bunun yerine düz eğik çizgi, değişiklik olurdu Eğer '\\'için'/'

Şunlarla çalışacak:

c:\foo\bar\hello\world

ve

c:\foo\bar\hellp\world\

(yani: eğik çizgiye ihtiyaç duymaz, bu yüzden kontrol etmeniz gerekmez.)

"Yalnızca Windows'ta SHCreateDirectoryEx () kullanın" demeden önce , SHCreateDirectoryEx () ' in kullanımdan kaldırıldığını ve Windows'un gelecekteki sürümlerinden herhangi bir zamanda kaldırılabileceğini unutmayın .

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

Küçük bir mod - yol ters eğik çizgi içeriyorsa bu işe yaramaz. Burada: `LPCTSTR szLast = _tcsrchr (szPathTree, '\\');` `Bunu eklemeniz yeterlidir:` `` if (nullptr == szLast) {szLast = _tcsrchr (szPathTree, '/'); } ``
Den-Jason

1
Bilgi için teşekkürler. Yol karışıksa ne olur? yani: c:\this\is\a/mixed/path\of\slashesTipik olarak Windows eğik çizgileri ters eğik çizgilerdir. Olması gereken şey, arayan kişi yolu temizlemeli ve bu yöntemi çağırmadan önce tüm eğik çizgilerin uygun olduğundan emin olmalıdır.
Andy

3

Bunun eski bir soru olduğunu biliyorum, ancak Google arama sonuçlarında üst sıralarda görünüyor ve burada verilen cevaplar gerçekten C ++ dilinde değil veya biraz fazla karmaşık.

Lütfen benim örneğimde createDirTree () 'nin çok basit olduğunu unutmayın çünkü tüm ağır kaldırma (hata kontrolü, yol doğrulama) yine de createDir () tarafından yapılmalıdır. Ayrıca, dizin zaten varsa createDir () true döndürmelidir, aksi halde her şey çalışmaz.

Bunu C ++ 'da şu şekilde yapardım:

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

Elbette createDir () işlevi sisteme özgü olacak ve diğer yanıtlarda linux için nasıl yazılacağına dair yeterince örnek var, bu yüzden atlamaya karar verdim.


1

Dir yoksa, oluşturun:

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

1

Burada pek çok yaklaşım açıklanmıştır, ancak bunların çoğunun kodunuza giden yolunuzun sabit kodlanması gerekir. Qt çerçevesinin iki sınıfı olan QDir ve QFileInfo kullanarak bu problem için kolay bir çözüm var. Zaten Linux ortamında olduğunuz için Qt'yi kullanmak kolay olmalıdır.

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

Bu Yola yazma erişiminiz olduğundan emin olun.


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

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

-pseçenek aradığım şeydir. Teşekkürler!
asgs

0

dirname()Dizin ağacını aşağıdan yukarıya hareket ettirmek için kullanan C / C ++ özyinelemeli işlevi burada . Mevcut bir atayı bulur bulmaz duracaktır.

#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

Diğerleri sana doğru cevabı verdi, ama yapabileceğin başka bir güzel şeyi daha göstereyim dedim:

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

Aşağıdaki yolları oluşturacaktır:

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

Küme parantezleri, hiyerarşinin aynı düzeyinde aynı anda birden çok dizin oluşturmanıza izin verirken, -pseçenek "gerektiğinde ana dizinler oluştur" anlamına gelir.


Paul'un cevabını gördükten sonra, benim (ve diğer birçok insanın) soruyu yanlış anladığımı fark ettim ...
tekerleme

Eğer birisi bunu sisteme ("mkdir -p / tmp / a / {b, c} / d") geçerek güncelleyebiliyorsa, çünkü sorular bunu kabukta yapmakla değil, C ++ ile yapmakla ilgili.
Lipis

Sanırım {a, b} hem sh türevi hem de csh türevi kabuklarda çalışacak. Yine de bir system () komutunda çalışıp çalışmayacağından emin değilim.
Paul Tomblin

1
@Lipis: Bunu system () aracılığıyla yapmak, OP'nin sorusu için iyi bir çözüm değil. @Andy: Bunu daha önce hiç düşünmemiştim, ancak "mkdir -p" yi "echo" ile değiştirerek test ettim ve "/ tmp / a / b / d / tmp / a / c / d" yazıyor, bu da bunu yapan kabuğun mkdir değil olduğunu gösteriyor.
rmeador

@rmeador: Eğer iyi bir çözüm değilse, önerebileceğiniz başka bir şey var mı? Bunu C ++ ile yapmak istiyorum ... bu benim sorunum kabuk aracılığıyla nasıl yapılacağı değil ..
Lipis
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.