14 ответов:
вот функция C, которая может быть скомпилирована с помощью компиляторов C++.
/* @(#)File: $RCSfile: mkpath.c,v $ @(#)Version: $Revision: 1.13 $ @(#)Last changed: $Date: 2012/07/15 00:40:37 $ @(#)Purpose: Create all directories in path @(#)Author: J Leffler @(#)Copyright: (C) JLSS 1990-91,1997-98,2001,2005,2008,2012 */ /*TABSTOP=4*/ #include "jlss.h" #include "emalloc.h" #include <errno.h> #ifdef HAVE_UNISTD_H #include <unistd.h> #endif /* HAVE_UNISTD_H */ #include <string.h> #include "sysstat.h" /* Fix up for Windows - inc mode_t */ typedef struct stat Stat; #ifndef lint /* Prevent over-aggressive optimizers from eliminating ID string */ const char jlss_id_mkpath_c[] = "@(#)$Id: mkpath.c,v 1.13 2012/07/15 00:40:37 jleffler Exp $"; #endif /* lint */ 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 = ''; 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> /* ** 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>на современных системах Unix (но было много проблем в 1990 году). И"jlss.h"объявляетmkpath().изменение между v1. 12 (предыдущий) и v1. 13 (выше) является тестом для
EEXISTнаdo_mkdir(). Это было указано как необходимое переключатель - спасибо, переключатель. Тестовый код был обновлен и воспроизведен проблема на MacBook Pro (2,3 ГГц Intel Core i7, работает Mac OS X 10.7.4), и предполагает, что проблема исправлена в редакции (но тестирование может показать только наличие ошибок, никогда их отсутствие).(официально дано разрешение использовать этот код для любых целей с атрибуцией.)
легко увеличить.Файловая система:
create_directories#include <boost/filesystem.hpp> //... boost::filesystem::create_directories("/tmp/a/b/c");возвращает:
trueесли новый каталог был создан, в противном случаеfalse.
system("mkdir -p /tmp/a/b/c")- Это самый короткий путь, я думаю (с точки зрения длины кода, не обязательно время выполнения).
Это не кросс-платформенный, но будет работать под Linux.
#include <sys/types.h> #include <sys/stat.h> int status; ... status = mkdir("/tmp/a/b/c", S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);С здесь. Возможно, вам придется сделать отдельные mkdirs для /tmp, /tmp/a, /tmp/a/b/ и затем /tmp/a/b/c, потому что в api C нет эквивалента флага-p. Будьте уверены, и игнорировать EEXISTS ошибки, когда вы делаете верхнего уровня.
вот мой пример кода (он работает как для Windows, так и Linux):
#include <iostream> #include <string> #include <sys/stat.h> // stat #include <errno.h> // errno, ENOENT, EEXIST #if defined(_WIN32) #include <direct.h> // _mkdir #endif bool isDirExist(const std::string& path) { #if defined(_WIN32) struct _stat info; if (_stat(path.c_str(), &info) != 0) { return false; } return (info.st_mode & _S_IFDIR) != 0; #else struct stat info; if (stat(path.c_str(), &info) != 0) { return false; } return (info.st_mode & S_IFDIR) != 0; #endif } bool makePath(const std::string& path) { #if defined(_WIN32) int ret = _mkdir(path.c_str()); #else mode_t mode = 0755; int ret = mkdir(path.c_str(), mode); #endif if (ret == 0) return true; switch (errno) { case ENOENT: // parent didn't exist, try to create it { int pos = path.find_last_of('/'); if (pos == std::string::npos) #if defined(_WIN32) pos = path.find_last_of('\'); if (pos == std::string::npos) #endif return false; if (!makePath( path.substr(0, pos) )) return false; } // now, try to create again #if defined(_WIN32) return 0 == _mkdir(path.c_str()); #else return 0 == mkdir(path.c_str(), mode); #endif case EEXIST: // done! return isDirExist(path); default: return false; } } int main(int argc, char* ARGV[]) { for (int i=1; i<argc; i++) { std::cout << "creating " << ARGV[i] << " ... " << (makePath(ARGV[i]) ? "OK" : "failed") << std::endl; } return 0; }использование:
$ makePath 1/2 folderA/folderB/folderC creating 1/2 ... OK creating folderA/folderB/folderC ... OK
Вы сказали " C++", но все здесь, кажется, думают " Bash shell."
Проверьте исходный код для gnu
mkdir; затем вы можете увидеть, как реализовать команды оболочки в C++.
это похоже на предыдущее, но работает вперед через строку, а не рекурсивно назад. Оставляет errno с правильным значением для последнего сбоя. Если есть Слэш, есть дополнительное время, сквозь петлю которого можно было бы избежать с помощью одного find_first_of() вне цикла или обнаружение / и постановка на 1. Эффективность одинакова независимо от того, настроены ли мы первым циклом или вызовом предварительного цикла, и сложность будет (немного) выше, когда использование предварительного цикла вызова.
#include <iostream> #include <string> #include <sys/stat.h> int mkpath(std::string s,mode_t mode) { size_t pre=0,pos; 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('/',pre))!=std::string::npos){ dir=s.substr(0,pos++); pre=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'; }
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; }
так что мне нужно
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_Hmkdirp.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 != '') { // Skip first character p++; // Find first slash or end while(*p != '' && *p != '/') p++; // Remember value from p char v = *p; // Write end of string at p *p = ''; // Create folder from path to '' 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 и временное изменение строки, просто сделайте
strdup()иfree()это потом.
поскольку этот пост занимает высокое место в Google для "создать дерево каталогов", я собираюсь опубликовать ответ, который будет работать для Windows - это будет работать с использованием Win32 API, скомпилированного для UNICODE или MBCS. Это перенесено из кода Марка выше.
поскольку это окна, с которыми мы работаем, разделители каталогов являются обратными косыми чертами, а не передними косыми чертами. Если вы предпочитаете прямые косые черты, измените
'\'до'/'Он будет работать с:
c:\foo\bar\hello\worldи
c:\foo\bar\hellp\world\(т. е.: не нужна косая черта, поэтому вам не нужно ее проверять.)
прежде чем сказать "просто использовать SHCreateDirectoryEx () в Windows", обратите внимание, что SHCreateDirectoryEx () является устаревшим и может быть удален в любое время из будущих версий Windows.
bool CreateDirectoryTree(LPCTSTR szPathTree, LPSECURITY_ATTRIBUTES lpSecurityAttributes = NULL){ bool bSuccess = false; const BOOL bCD = CreateDirectory(szPathTree, lpSecurityAttributes); DWORD dwLastError = 0; if(!bCD){ dwLastError = GetLastError(); }else{ return true; } switch(dwLastError){ case ERROR_ALREADY_EXISTS: bSuccess = true; break; case ERROR_PATH_NOT_FOUND: { TCHAR szPrev[MAX_PATH] = {0}; LPCTSTR szLast = _tcsrchr(szPathTree,'\'); _tcsnccpy(szPrev,szPathTree,(int)(szLast-szPathTree)); if(CreateDirectoryTree(szPrev,lpSecurityAttributes)){ bSuccess = CreateDirectory(szPathTree,lpSecurityAttributes)!=0; if(!bSuccess){ bSuccess = (GetLastError()==ERROR_ALREADY_EXISTS); } }else{ bSuccess = false; } } break; default: bSuccess = false; break; } return bSuccess; }
Я знаю, что это старый вопрос, но он отображается высоко в результатах поиска google, и ответы, представленные здесь, на самом деле не на C++ или немного слишком сложны.
обратите внимание, что в моем примере createDirTree() очень просто, потому что все тяжелые подъемы (проверка ошибок, проверка пути) должны быть сделаны createDir() в любом случае. Также createDir() должен возвращать true, если каталог уже существует или все это не будет работать.
вот как я бы сделал это C++:
#include <iostream> #include <string> bool createDir(const std::string dir) { std::cout << "Make sure dir is a valid path, it does not exist and create it: " << dir << std::endl; return true; } bool createDirTree(const std::string full_path) { size_t pos = 0; bool ret_val = true; while(ret_val == true && pos != std::string::npos) { pos = full_path.find('/', pos + 1); ret_val = createDir(full_path.substr(0, pos)); } return ret_val; } int main() { createDirTree("/tmp/a/b/c"); return 0; }конечно, функция createDir () будет специфичной для системы, и в других ответах уже есть достаточно примеров, как написать ее для linux, поэтому я решил пропустить ее.
Если dir не существует, создайте его:
boost::filesystem::create_directories(boost::filesystem::path(output_file).parent_path().string().c_str());
остальные получили правильный ответ, но я подумал, что продемонстрирую еще одну аккуратную вещь, которую вы можете сделать:
mkdir -p /tmp/a/{b,c}/dсоздать следующие пути:
/tmp/a/b/d /tmp/a/c/dфигурные скобки позволяют создавать сразу несколько каталогов на одном уровне иерархии, в то время как
-pопция "создать родительские каталоги по мере необходимости".
Comments