¿Cómo puedo crear un árbol de directorios en C ++ / Linux?

Quiero una manera fácil de crear múltiples directorios en C ++ / Linux.

Por ejemplo, quiero guardar un archivo lola.file en el directorio:

/tmp/a/b/c 

pero si los directorios no están allí, quiero que se creen automágicamente. Un ejemplo de trabajo sería perfecto.

Aquí hay una función C que se puede comstackr con comstackdores 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  #ifdef HAVE_UNISTD_H #include  #endif /* HAVE_UNISTD_H */ #include  #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 = '\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  /* ** 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 */ 

Las macros STRDUP() y FREE() son versiones de control de strdup() de strdup() y free() , declaradas en emalloc.h (e implementadas en emalloc.c y estrdup.c ). El "sysstat.h" trata con las versiones rotas de y puede ser reemplazado por en los sistemas Unix modernos (pero hubo muchos problemas en 1990). Y "jlss.h" declara mkpath() .

El cambio entre v1.12 (previo) y v1.13 (arriba) es la prueba para EEXIST en do_mkdir() . Esto fue señalado como necesario por Switch - gracias, Switch. El código de prueba se ha actualizado y reproduce el problema en una MacBook Pro (Intel Core i7 a 2,3 GHz, con Mac OS X 10.7.4), y sugiere que el problema se corrige en la revisión (pero las pruebas solo pueden mostrar la presencia de errores) , nunca su ausencia).

(Por la presente, se le otorga permiso para usar este código para cualquier propósito con atribución).

Fácil con Boost.Filesystem: create_directories

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

Devuelve: true si se creó un nuevo directorio; de lo contrario, es false .

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

es la forma más corta en que puedo pensar (en términos de la longitud del código, no necesariamente del tiempo de ejecución).

No es multiplataforma, pero funcionará bajo Linux.

 #include  #include  int status; ... status = mkdir("/tmp/a/b/c", S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); 

Desde aquí . Puede que tenga que hacer mkdirs separados para / tmp, / tmp / a, / tmp / a / b / y luego / tmp / a / b / c porque no hay un equivalente del distintivo -p en la api C. Asegúrese e ignore el EEXISTS errno mientras está haciendo los niveles superiores.

Aquí está mi ejemplo de código (funciona tanto para Windows como para Linux):

 #include  #include  #include  // stat #include  // errno, ENOENT, EEXIST #if defined(_WIN32) #include  // _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 

Uso:

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

Dijiste “C ++” pero todos aquí parecen pensar “Bash shell”.

Mira el código fuente para gnu mkdir ; entonces puedes ver cómo implementar los comandos de shell en C ++.

Esto es similar al anterior pero avanza a través de la cadena en lugar de recursivamente hacia atrás. Deja errno con el valor correcto para la última falla. Si hay una barra diagonal, hay un tiempo extra a través del ciclo que podría haberse evitado mediante un find_first_of () fuera del ciclo o al detectar el pre / líder antes de 1. La eficiencia es la misma ya sea que nos configuremos mediante un primer ciclo o una llamada pre loop, y la complejidad sería (un poco) mayor cuando se usa la llamada pre-loop.

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

Necesito mkdirp() hoy, y encontré las soluciones en esta página demasiado complicadas. Por lo tanto, escribí un fragmento bastante breve, que se puede copiar fácilmente para otros que tropiecen con este hilo y se preguntan por qué necesitamos tantas líneas de código.

mkdirp.h

 #ifndef MKDIRP_H #define MKDIRP_H #include  #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  bool mkdirp(const char* path, mode_t mode) { // const cast for hack char* p = const_cast(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; } 

Si no te gusta el fundido de const y la modificación temporal de la cadena, simplemente haz un strdup() y free() después.

Dado que este puesto tiene una clasificación alta en Google para “Crear árbol de directorios”, voy a publicar una respuesta que funcionará para Windows; esto funcionará utilizando Win32 API comstackda para UNICODE o MBCS. Esto está portado desde el código de Mark arriba.

Dado que se trata de Windows con el que estamos trabajando, los separadores de directorios son BACK-slashes, no barras diagonales. Si prefieres tener barras diagonales, cambia '\\' a '/'

Funcionará con:

 c:\foo\bar\hello\world 

y

 c:\foo\bar\hellp\world\ 

(es decir: no necesita barra posterior, por lo que no tiene que comprobarlo).

Antes de decir “Simplemente use SHCreateDirectoryEx () en Windows”, tenga en cuenta que SHCreateDirectoryEx () está en desuso y podría eliminarse en cualquier momento de futuras versiones de 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; } 

Sé que es una vieja pregunta, pero aparece en los resultados de búsqueda de Google y las respuestas proporcionadas aquí no están realmente en C ++ o son demasiado complicadas.

Tenga en cuenta que en mi ejemplo createDirTree () es muy simple porque todo el trabajo pesado (comprobación de errores, validación de ruta) debe ser realizado por createDir () de todos modos. También createDir () debería devolver true si el directorio ya existe o todo no funcionará.

Así es como lo haría en C ++:

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

Por supuesto, la función createDir () será específica del sistema y ya hay suficientes ejemplos en otras respuestas sobre cómo escribirlo para Linux, así que decidí omitirlo.

Si el directorio no existe, créelo:

 boost::filesystem::create_directories(boost::filesystem::path(output_file).parent_path().string().c_str()); 
 mkdir -p /dir/to/the/file touch /dir/to/the/file/thefile.ending 

Los demás te dieron la respuesta correcta, pero pensé que podría demostrar otra cosa buena que puedes hacer:

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

Creará las siguientes rutas:

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

Las llaves le permiten crear múltiples directorios a la vez en el mismo nivel de la jerarquía, mientras que la opción -p significa “crear directorios principales según sea necesario”.