Avec C++17 ou plus, il y a l'en-tête standard. <filesystem>
avec fonction std::filesystem::create_directories
qui devraient être utilisés dans les programmes C++ modernes. Les fonctions standard C++ n'ont pas les autorisations explicites spécifiques à POSIX. (mode) spécifique à POSIX.
Cependant, voici une fonction C qui peut être compilée avec les compilateurs 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"
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 */
Les macros STRDUP()
y FREE()
sont des versions de contrôle d'erreurs de strdup()
y free()
déclaré dans emalloc.h
(et mis en œuvre dans emalloc.c
y estrdup.c
). Le site "sysstat.h"
L'en-tête traite des versions brisées de <sys/stat.h>
et peut être remplacé par <sys/stat.h>
sur les systèmes Unix modernes (mais il y a de nombreux problèmes en 1990). Et "mkpath.h"
déclare mkpath()
.
Le changement entre la v1.12 (version originale de la réponse) et la v1.13 (version amendée de la réponse) était le test de EEXIST
sur do_mkdir()
. Cette mesure a été jugée nécessaire par Interrupteur - remercier vous, Switch. Le code de test a été mis à jour et a reproduit le problème sur un MacBook Pro (2.3GHz Intel Core i7, exécutant Mac OS X 10.7.4), et suggère que que le problème est corrigé dans la révision (mais les tests ne peuvent montrer que la présence de bogues, jamais leur absence). Le code présenté est maintenant la v1.16 ; il y a eu des changements cosmétiques ou administratifs. administratifs ont été effectués depuis la v1.13 (comme l'utilisation de mkpath.h
au lieu de jlss.h
et inclure <unistd.h>
sans condition dans le code de test uniquement). Il est raisonnable d'argumenter que "sysstat.h"
doit être remplacé par <sys/stat.h>
sauf si vous avez un système exceptionnellement récalcitrant.
(Vous êtes par la présente autorisé à utiliser ce code à n'importe quelle fin avec attribution).
Ce code est disponible dans mon SOQ (Stack Overflow Questions) sur GitHub comme fichiers mkpath.c
y mkpath.h
(etc.) dans le src/so-0067-5039 sous-répertoire.
0 votes
Le C++ ne dispose d'aucune fonction intégrée pour la création de répertoires et d'arbres. en soi . Vous devrez utiliser le C et les appels système ou une bibliothèque externe comme Boost. Le C et les appels système dépendent de la plate-forme.
7 votes
@noloader Merci beaucoup... mais je pense qu'après 4 ans, j'ai trouvé ma réponse comme vous pouvez le voir ci-dessous de 13 façons différentes...
0 votes
Oui, j'ai été surpris que personne n'ait explicitement indiqué que vous ne pouviez pas le faire en C++ (en supposant que vous vouliez une méthode portable en C++ qui fonctionne sous Linux). Mais vous le saviez probablement ;). Il y avait beaucoup de bonnes suggestions pour le code C non portable, cependant.
0 votes
Qu'est-ce que "C++/Linux" ?
3 votes
@LightnessRacesinOrbit Ce sont mes années universitaires en C++ sur Linux :)