C ++ nie posiada żadnych wbudowanych urządzeń do tworzenia katalogów i drzew per se . Będziesz musiał użyć C i wywołań systemowych lub biblioteki zewnętrznej, takiej jak Boost. C i wywołania systemowe będą zależne od platformy.
jww
6
@noloader Wielkie dzięki stary ... ale myślę, że po 4 latach otrzymałem odpowiedź, jak widać poniżej na 13 różnych sposobów ...
Lipis
Tak, byłem zaskoczony, że nikt wyraźnie nie stwierdził, że nie możesz tego zrobić w C ++ (zakładając, że chcesz mieć przenośną metodę w C ++, która działałaby w systemie Linux). Ale pewnie o tym wiedziałeś;). Było jednak wiele dobrych sugestii dotyczących nieprzenośnego kodu C.
jww
Co to jest „C ++ / Linux”?
Wyścigi lekkości na orbicie
3
@LightnessRacesinOrbit To moje lata uniwersyteckie w C ++ na Linuksie :)
Lipis
Odpowiedzi:
59
W C ++ 17 lub nowszym istnieje standardowy nagłówek <filesystem>z funkcją,
std::filesystem::create_directories
który powinien być używany we współczesnych programach C ++. Standardowe funkcje C ++ nie mają jednak specyficznego dla POSIX jawnego argumentu permissions (mode).
Jednak tutaj jest funkcja C, którą można skompilować za pomocą kompilatorów 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"typedefstruct stat Stat;staticint do_mkdir(constchar*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;}elseif(!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(constchar*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 */
Makra STRDUP()i FREE()są wersjami sprawdzającymi błędy programu
strdup()i free(), zadeklarowanymi w emalloc.h(i zaimplementowanymi w
emalloc.ci estrdup.c). Do "sysstat.h"oferty nagłówek z rozbitych wersjach <sys/stat.h>
i może być zastąpiony <sys/stat.h>na nowoczesnych systemach Unix (ale było wiele problemów z powrotem w 1990 roku). I "mkpath.h"oświadczamkpath() .
Zmiana między wersją 1.12 (oryginalna wersja odpowiedzi) a wersją 1.13 (poprawiona wersja odpowiedzi) była testem EEXISTw
do_mkdir(). Zwrócił na to uwagę
Switch - dziękuję Switch. Kod testowy został zaktualizowany i odtworzył problem na MacBooku Pro (2,3 GHz Intel Core i7, z systemem Mac OS X 10.7.4) i sugeruje, że problem został rozwiązany w wersji (ale testy mogą tylko wykazać obecność błędów , nigdy ich nieobecność). Wyświetlany kod to teraz wersja 1.16; od wersji 1.13 wprowadzono zmiany kosmetyczne lub administracyjne (takie jak używanie mkpath.hzamiast jlss.hi <unistd.h>bezwarunkowe uwzględnianie tylko w kodzie testowym). Rozsądnie jest argumentować, że "sysstat.h"należy go zastąpić,
<sys/stat.h>chyba że masz niezwykle oporny system.
(Otrzymujesz zgodę na użycie tego kodu w dowolnym celu z podaniem źródła).
Ten kod jest dostępny w moim
repozytorium SOQ (Stack Overflow Questions) na GitHub jako pliki mkpath.ci
mkpath.h(itp.) W
podkatalogu src / so-0067-5039 .
Z pewnością jest szybszy niż system. System ma dużo narzutów. Zasadniczo proces musi zostać rozwidlony, a następnie załadować co najmniej dwa pliki binarne (jeden prawdopodobnie będzie już w pamięci podręcznej), z których jeden będzie kolejnym widelcem drugiego, ...
ypnos
1
Zapomniałem: I wtedy "mkdir -p" zrobi co najmniej to samo, co zamieszczony powyżej kod!
ypnos
7
W tym kodzie jest subtelny stan wyścigu, w który trafiłem. Dzieje się tak tylko wtedy, gdy wiele programów uruchamia się jednocześnie i tworzy tę samą ścieżkę do folderu. Poprawka polega na dodaniu, if (errno != EEXIST) { status = -1; }gdy mkdir zawiedzie.
Przełącz
2
@Switch: Dzięki. To jest problem z używaniem stat()wcześniej mkdir(); jest to problem TOCTOU (czas sprawdzenia, czas użycia). Próbowałem łaskotać błąd skryptem powłoki uruchamiającym 13 procesów w tle, tworząc tę samą 29-elementową ścieżkę i nie udało mi się go trafić. Następnie włamałem się do programu testowego, aby rozwidlić 20 razy i kazałem każdemu dziecku spróbować, a to udało się trafić w błąd. Naprawiony kod będzie miał if (mkdir(path, mode) != 0 && errno != EEXIST) status = -1;. To nie pokazuje błędu.
Jonathan Leffler,
2
@DavidMerinos: to nagłówki ( jlss.h, emalloc.h), a nie biblioteki. Jednak kod jest dostępny w moim SOQ (przepełnienie stosu pytań) repozytorium na GitHub jako pliki jlss.h, emalloc.ca emalloc.hw libsoq / src podkatalogu. Będziesz też potrzebować posixver.hi kilka innych ( debug.h,stderr.c , stderr.h- Myślę, że to wszystko, ale to, czego potrzebujesz powinny być w tym katalogu).
Cóż, większość bibliotek Boost obsługuje tylko nagłówki, co oznacza, że nie ma narzutów poza tym, czego używasz. W przypadku Boost.Filesystem wymaga jednak kompilacji. Na moim dysku skompilowana biblioteka waży ~ 60KB.
Benoît
1
@ Lipis: proszę sprecyzować, jaki jest twój system wbudowany. Uważam, że powinien być dostępny w prawie każdej dystrybucji Linuksa.
Benoît
4
Jeśli chodzi o kompilatory C ++ 11, o których wspomniał @danijar, komentarz tutaj wyjaśnił to: 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.
IMHO: W każdym moim projekcie, który ma na celu zrobienie czegoś znaczącego i przetrwanie próby czasu, DOBRZE warto skompilować taki zestaw niezwykle przydatnych i potężnych standardowych narzędzi, jak boost. Mnóstwo tego już trafiło do standardowego C ++, a na pewno jeszcze więcej. Wypróbuj, trzymaj się tego, odniesiesz korzyści, jeśli masz więcej niż trywialne potrzeby i nie chcesz wymyślać koła na nowo. :-)
moodboom
42
system("mkdir -p /tmp/a/b/c")
to najkrótszy sposób, jaki mogę sobie wyobrazić (pod względem długości kodu, niekoniecznie czasu wykonania).
Nie jest to platforma wieloplatformowa, ale będzie działać pod Linuksem.
Od tutaj . Może być konieczne utworzenie oddzielnych katalogów mkdir dla / tmp, / tmp / a, / tmp / a / b /, a następnie / tmp / a / b / c, ponieważ nie ma odpowiednika opcji -p w interfejsie API C. Upewnij się i zignoruj EEXISTS errno podczas wykonywania zadań wyższego poziomu.
Ciekawostka: przynajmniej Solaris i HP / UX mają mkdirp (), chociaż najwyraźniej nie jest to optymalne do przenoszenia.
Martin Carpenter,
o to chodzi ... że nie chcę nazywać tych wszystkich funkcji osobno.
Lipis
Wywołanie mkdir kilka razy będzie o wiele szybsze niż jednokrotne wywołanie systemu.
Paul Tomblin,
Nie rozumiem, co sugerujesz: dzwonisz do mkdir 4 razy z różnymi argumentami? ("/tmp/",...), ("/tmp/a/",...), ("/tmp/a/b/",...),("/tmp/a/b/c/",...)
Antonio
1
Ponownie, wykonanie tego samego połączenia trzy razy jest dość trywialne. Chodzi o to, aby dać ludziom wystarczającą ilość informacji, aby mogli napisać kod, a nie napisać kod za nich.
Paul Tomblin
25
Oto mój przykład kodu (działa zarówno w systemie Windows, jak i Linux):
Popieram ten komentarz! Znalezienie przenośnego sposobu w C ++ na utworzenie katalogu nie jest (zaskakująco) prostym zadaniem. Ta odpowiedź wymaga więcej głosów pozytywnych.
Manuel Lafond
1
W systemie Windows isDirExist nie działa, jeśli końcowym znakiem jest ukośnik odwrotny. Zawsze zwraca fałsz. Muszę zmodyfikować kod do: std :: string dirPath (ścieżka); while ('\\' == * dirPath.rbegin ()) dirPath.pop_back (); ... a następnie oczywiście przekaż dirPath.c_str () w wywołaniu _stat.
MiloDC,
Interfejs API systemu Windows ma „nazwy niezgodne z ANSI na potrzeby zgodności”, które stat(związane z __STDC__) nie wymagają testu prekompilatora.
Sandburg
18
Należy zauważyć, że począwszy od systemu plików C ++ 17 interfejs jest częścią standardowej biblioteki. Oznacza to, że można utworzyć katalogi:
Jest to podobne do poprzedniego, ale działa w przód przez łańcuch zamiast rekurencyjnie do tyłu. Pozostawia errno odpowiednią wartość dla ostatniej awarii. Jeśli występuje wiodący ukośnik, istnieje dodatkowy czas w pętli, którego można było uniknąć za pomocą funkcji find_first_of () poza pętlą lub przez wykrycie wiodącego / i ustawienie pre na 1. Wydajność jest taka sama, niezależnie od tego, czy zostaniemy skonfigurowani przez pierwsza pętla lub wywołanie przed pętlą, a złożoność byłaby (nieco) większa podczas korzystania z wywołania przed pętlą.
#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 lengthif((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';}
Więc potrzebuję mkdirp()dzisiaj, a rozwiązania na tej stronie okazały się zbyt skomplikowane. Dlatego napisałem dość krótki fragment, który można łatwo skopiować dla innych, którzy natkną się na ten wątek, i zastanawiam się, dlaczego potrzebujemy tak wielu wierszy kodu.
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(constchar* path,mode_t mode = DEFAULT_MODE);#endif// MKDIRP_H
mkdirp.cpp
#include<errno.h>bool mkdirp(constchar* path,mode_t mode){// const cast for hackchar* p =const_cast<char*>(path);// Do mkdir for each slash until end of string or errorwhile(*p !='\0'){// Skip first character
p++;// Find first slash or endwhile(*p !='\0'&&*p !='/') p++;// Remember value from pchar v =*p;// Write end of string at p*p ='\0';// Create folder from path to '\0' inserted at pif(mkdir(path, mode)==-1&& errno != EEXIST){*p = v;returnfalse;}// Restore path to it's former glory*p = v;}returntrue;}
Jeśli nie lubisz rzucać const i tymczasowo modyfikować łańcucha, po prostu zrób a strdup()i free()potem.
Zamieszczono też w streszczeniu, więc nie zapomnę, gdzie go wstawię
jonasfj
2
Jest złem próbować modyfikować ciąg, który jest przekazywany jako stała. Poza tym może doprowadzić do dramatycznych niepowodzeń, jeśli kiedykolwiek zostanie przekazany dosłowny ciąg.
Jonathan Leffler
2
Doskonale zgadza się .... to faktycznie jest złe ... prawdopodobnie strcpy by to poprawił ...
jonasfj
3
Ponieważ ten post zajmuje wysokie miejsce w Google w kategorii „Utwórz drzewo katalogów”, zamierzam opublikować odpowiedź, która będzie działać w systemie Windows - będzie działać przy użyciu interfejsu API Win32 skompilowanego dla UNICODE lub MBCS. Jest to przeniesione z powyższego kodu Marka.
Ponieważ jest to system Windows, z którym pracujemy, separatorami katalogów są ukośniki BACK, a nie ukośniki w przód. Jeśli wolisz ukośniki, zmień '\\'na'/'
Będzie działać z:
c:\foo\bar\hello\world
i
c:\foo\bar\hellp\world\
(tj .: nie wymaga końcowego ukośnika, więc nie musisz go sprawdzać).
Zanim powiesz „Po prostu użyj SHCreateDirectoryEx () w Windows”, zwróć uwagę, że SHCreateDirectoryEx () jest przestarzała i może zostać usunięta w dowolnym momencie z przyszłych wersji systemu Windows.
Jeden mały mod - jeśli ścieżka zawiera odwrotne ukośniki, to nie działa. Tutaj: `LPCTSTR szLast = _tcsrchr (szPathTree, '\\');` Wystarczy dodać to: `` `` if (nullptr == szLast) {szLast = _tcsrchr (szPathTree, '/'); } ``
Den-Jason
1
Dzięki za informację. Co się stanie, jeśli ścieżka jest mieszana? tj.: c:\this\is\a/mixed/path\of\slashesZazwyczaj ukośniki systemu Windows są ukośnikami odwrotnymi. Powinno się zdarzyć, że wywołujący powinien oczyścić ścieżkę i upewnić się, że wszystkie ukośniki są prawidłowe przed wywołaniem tej metody.
Andy
3
Wiem, że to stare pytanie, ale pojawia się wysoko w wynikach wyszukiwania Google, a podane tutaj odpowiedzi nie są tak naprawdę w C ++ lub są nieco zbyt skomplikowane.
Zwróć uwagę, że w moim przykładzie createDirTree () jest bardzo proste, ponieważ całe podnoszenie ciężarów (sprawdzanie błędów, walidacja ścieżki) i tak musi być wykonane przez createDir (). Również createDir () powinno zwrócić true, jeśli katalog już istnieje lub całość nie zadziała.
Oto jak zrobiłbym to w 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;returntrue;}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");return0;}
Oczywiście funkcja createDir () będzie specyficzna dla systemu, aw innych odpowiedziach jest już wystarczająco dużo przykładów, jak napisać ją dla Linuksa, więc zdecydowałem się ją pominąć.
Opisano tutaj tak wiele podejść, ale większość z nich wymaga twardego zakodowania ścieżki do kodu. Istnieje proste rozwiązanie tego problemu, używając QDir i QFileInfo, dwóch klas frameworka Qt. Ponieważ jesteś już w środowisku Linux, korzystanie z Qt powinno być łatwe.
QString qStringFileName("path/to/the/file/that/dont/exist.txt");QDir dir =QFileInfo(qStringFileName).dir();if(!dir.exists()){
dir.mkpath(dir.path());}
Upewnij się, że masz dostęp do zapisu w tej ścieżce.
Oto rekurencyjna funkcja C / C ++, która wykorzystuje dirname()do przechodzenia z dołu do góry drzewa katalogów. Zatrzyma się, gdy tylko znajdzie istniejącego przodka.
#include<libgen.h>#include<string.h>int create_dir_tree_recursive(constchar*path,constmode_t mode){if(strcmp(path,"/")==0)// No need of checking if we are at root.return0;// 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;}return0;}
Inni dali ci właściwą odpowiedź, ale pomyślałem, że zademonstruję inną fajną rzecz, którą możesz zrobić:
mkdir -p /tmp/a/{b,c}/d
Stworzy następujące ścieżki:
/tmp/a/b/d
/tmp/a/c/d
Nawiasy umożliwiają tworzenie wielu katalogów jednocześnie na tym samym poziomie hierarchii, podczas gdy -popcja oznacza „utwórz katalogi nadrzędne według potrzeb”.
po zobaczeniu odpowiedzi Paula zdaję sobie sprawę, że ja (i wiele innych osób) źle zrozumiałem pytanie ...
rmeador
Jeśli ktoś może to po prostu zaktualizować, przechodząc na system ("mkdir -p / tmp / a / {b, c} / d"), ponieważ pytania nie dotyczą robienia tego w powłoce .. ale przez C ++.
Lipis
Myślę, że {a, b} będzie działać zarówno w powłokach pochodzących z sh, jak i csh. Nie jestem jednak pewien, czy zadziała w poleceniu system ().
Paul Tomblin,
1
@Lipis: robienie tego przez system () nie jest dobrym rozwiązaniem na pytanie OP. @Andy: Nigdy wcześniej tego nie brałem pod uwagę, ale właśnie przetestowałem to, zastępując „mkdir -p” słowem „echo” i wypisuje „/ tmp / a / b / d / tmp / a / c / d”, co sugeruje, że robi to powłoka, a nie mkdir.
rmeador
@rmeador: jeśli to nie jest dobre rozwiązanie, czy masz coś innego do zaproponowania? Chcę to zrobić za pomocą C ++ ... to mój problem, a nie jak to zrobić przez powłokę ..
Odpowiedzi:
W C ++ 17 lub nowszym istnieje standardowy nagłówek
<filesystem>
z funkcją,std::filesystem::create_directories
który powinien być używany we współczesnych programach C ++. Standardowe funkcje C ++ nie mają jednak specyficznego dla POSIX jawnego argumentu permissions (mode).Jednak tutaj jest funkcja C, którą można skompilować za pomocą kompilatorów C ++.
Makra
STRDUP()
iFREE()
są wersjami sprawdzającymi błędy programustrdup()
ifree()
, zadeklarowanymi wemalloc.h
(i zaimplementowanymi wemalloc.c
iestrdup.c
). Do"sysstat.h"
oferty nagłówek z rozbitych wersjach<sys/stat.h>
i może być zastąpiony<sys/stat.h>
na nowoczesnych systemach Unix (ale było wiele problemów z powrotem w 1990 roku). I"mkpath.h"
oświadczamkpath()
.Zmiana między wersją 1.12 (oryginalna wersja odpowiedzi) a wersją 1.13 (poprawiona wersja odpowiedzi) była testem
EEXIST
wdo_mkdir()
. Zwrócił na to uwagę Switch - dziękuję Switch. Kod testowy został zaktualizowany i odtworzył problem na MacBooku Pro (2,3 GHz Intel Core i7, z systemem Mac OS X 10.7.4) i sugeruje, że problem został rozwiązany w wersji (ale testy mogą tylko wykazać obecność błędów , nigdy ich nieobecność). Wyświetlany kod to teraz wersja 1.16; od wersji 1.13 wprowadzono zmiany kosmetyczne lub administracyjne (takie jak używaniemkpath.h
zamiastjlss.h
i<unistd.h>
bezwarunkowe uwzględnianie tylko w kodzie testowym). Rozsądnie jest argumentować, że"sysstat.h"
należy go zastąpić,<sys/stat.h>
chyba że masz niezwykle oporny system.(Otrzymujesz zgodę na użycie tego kodu w dowolnym celu z podaniem źródła).
Ten kod jest dostępny w moim repozytorium SOQ (Stack Overflow Questions) na GitHub jako pliki
mkpath.c
imkpath.h
(itp.) W podkatalogu src / so-0067-5039 .źródło
if (errno != EEXIST) { status = -1; }
gdy mkdir zawiedzie.stat()
wcześniejmkdir()
; jest to problem TOCTOU (czas sprawdzenia, czas użycia). Próbowałem łaskotać błąd skryptem powłoki uruchamiającym 13 procesów w tle, tworząc tę samą 29-elementową ścieżkę i nie udało mi się go trafić. Następnie włamałem się do programu testowego, aby rozwidlić 20 razy i kazałem każdemu dziecku spróbować, a to udało się trafić w błąd. Naprawiony kod będzie miałif (mkdir(path, mode) != 0 && errno != EEXIST) status = -1;
. To nie pokazuje błędu.jlss.h
,emalloc.h
), a nie biblioteki. Jednak kod jest dostępny w moim SOQ (przepełnienie stosu pytań) repozytorium na GitHub jako plikijlss.h
,emalloc.c
aemalloc.h
w libsoq / src podkatalogu. Będziesz też potrzebowaćposixver.h
i kilka innych (debug.h
,stderr.c
,stderr.h
- Myślę, że to wszystko, ale to, czego potrzebujesz powinny być w tym katalogu).Łatwe dzięki Boost.
create_directories
Zwraca:
true
jeśli utworzono nowy katalog, w przeciwnym raziefalse
.źródło
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.
to najkrótszy sposób, jaki mogę sobie wyobrazić (pod względem długości kodu, niekoniecznie czasu wykonania).
Nie jest to platforma wieloplatformowa, ale będzie działać pod Linuksem.
źródło
Od tutaj . Może być konieczne utworzenie oddzielnych katalogów mkdir dla / tmp, / tmp / a, / tmp / a / b /, a następnie / tmp / a / b / c, ponieważ nie ma odpowiednika opcji -p w interfejsie API C. Upewnij się i zignoruj EEXISTS errno podczas wykonywania zadań wyższego poziomu.
źródło
("/tmp/",...)
,("/tmp/a/",...)
,("/tmp/a/b/",...)
,("/tmp/a/b/c/",...)
Oto mój przykład kodu (działa zarówno w systemie Windows, jak i Linux):
Stosowanie:
źródło
stat
(związane z__STDC__
) nie wymagają testu prekompilatora.Należy zauważyć, że począwszy od systemu plików C ++ 17 interfejs jest częścią standardowej biblioteki. Oznacza to, że można utworzyć katalogi:
Więcej informacji tutaj: https://en.cppreference.com/w/cpp/filesystem/create_directory
Dodatkowo, z gcc, trzeba "-std = c ++ 17" do CFLAGS. I „-lstdc ++ fs” do LDLIBS. Ten ostatni potencjalnie nie będzie potrzebny w przyszłości.
źródło
Jest to podobne do poprzedniego, ale działa w przód przez łańcuch zamiast rekurencyjnie do tyłu. Pozostawia errno odpowiednią wartość dla ostatniej awarii. Jeśli występuje wiodący ukośnik, istnieje dodatkowy czas w pętli, którego można było uniknąć za pomocą funkcji find_first_of () poza pętlą lub przez wykrycie wiodącego / i ustawienie pre na 1. Wydajność jest taka sama, niezależnie od tego, czy zostaniemy skonfigurowani przez pierwsza pętla lub wywołanie przed pętlą, a złożoność byłaby (nieco) większa podczas korzystania z wywołania przed pętlą.
źródło
Powiedziałeś „C ++”, ale wydaje się, że wszyscy tutaj myślą „powłoka bash”.
Sprawdź kod źródłowy GNU
mkdir
; wtedy możesz zobaczyć, jak zaimplementować polecenia powłoki w C ++.źródło
źródło
Więc potrzebuję
mkdirp()
dzisiaj, a rozwiązania na tej stronie okazały się zbyt skomplikowane. Dlatego napisałem dość krótki fragment, który można łatwo skopiować dla innych, którzy natkną się na ten wątek, i zastanawiam się, dlaczego potrzebujemy tak wielu wierszy kodu.mkdirp.h
mkdirp.cpp
Jeśli nie lubisz rzucać const i tymczasowo modyfikować łańcucha, po prostu zrób a
strdup()
ifree()
potem.źródło
Ponieważ ten post zajmuje wysokie miejsce w Google w kategorii „Utwórz drzewo katalogów”, zamierzam opublikować odpowiedź, która będzie działać w systemie Windows - będzie działać przy użyciu interfejsu API Win32 skompilowanego dla UNICODE lub MBCS. Jest to przeniesione z powyższego kodu Marka.
Ponieważ jest to system Windows, z którym pracujemy, separatorami katalogów są ukośniki BACK, a nie ukośniki w przód. Jeśli wolisz ukośniki, zmień
'\\'
na'/'
Będzie działać z:
i
(tj .: nie wymaga końcowego ukośnika, więc nie musisz go sprawdzać).
Zanim powiesz „Po prostu użyj SHCreateDirectoryEx () w Windows”, zwróć uwagę, że SHCreateDirectoryEx () jest przestarzała i może zostać usunięta w dowolnym momencie z przyszłych wersji systemu Windows.
źródło
c:\this\is\a/mixed/path\of\slashes
Zazwyczaj ukośniki systemu Windows są ukośnikami odwrotnymi. Powinno się zdarzyć, że wywołujący powinien oczyścić ścieżkę i upewnić się, że wszystkie ukośniki są prawidłowe przed wywołaniem tej metody.Wiem, że to stare pytanie, ale pojawia się wysoko w wynikach wyszukiwania Google, a podane tutaj odpowiedzi nie są tak naprawdę w C ++ lub są nieco zbyt skomplikowane.
Zwróć uwagę, że w moim przykładzie createDirTree () jest bardzo proste, ponieważ całe podnoszenie ciężarów (sprawdzanie błędów, walidacja ścieżki) i tak musi być wykonane przez createDir (). Również createDir () powinno zwrócić true, jeśli katalog już istnieje lub całość nie zadziała.
Oto jak zrobiłbym to w C ++:
Oczywiście funkcja createDir () będzie specyficzna dla systemu, aw innych odpowiedziach jest już wystarczająco dużo przykładów, jak napisać ją dla Linuksa, więc zdecydowałem się ją pominąć.
źródło
Jeśli katalog nie istnieje, utwórz go:
źródło
Opisano tutaj tak wiele podejść, ale większość z nich wymaga twardego zakodowania ścieżki do kodu. Istnieje proste rozwiązanie tego problemu, używając QDir i QFileInfo, dwóch klas frameworka Qt. Ponieważ jesteś już w środowisku Linux, korzystanie z Qt powinno być łatwe.
Upewnij się, że masz dostęp do zapisu w tej ścieżce.
źródło
źródło
-p
rozwiązaniem jest to, czego szukam. Dzięki!Oto rekurencyjna funkcja C / C ++, która wykorzystuje
dirname()
do przechodzenia z dołu do góry drzewa katalogów. Zatrzyma się, gdy tylko znajdzie istniejącego przodka.źródło
Inni dali ci właściwą odpowiedź, ale pomyślałem, że zademonstruję inną fajną rzecz, którą możesz zrobić:
Stworzy następujące ścieżki:
Nawiasy umożliwiają tworzenie wielu katalogów jednocześnie na tym samym poziomie hierarchii, podczas gdy
-p
opcja oznacza „utwórz katalogi nadrzędne według potrzeb”.źródło