system("mkdir -p /tmp/a/b/c")
私が考えることができる最短の方法です(コードの長さに関して、必ずしも実行時間ではありません)。
クロスプラットフォームではありませんが、Linux で動作します。
Boost.Filesystem で簡単:create_directories
#include <boost/filesystem.hpp>
//...
boost::filesystem::create_directories("/tmp/a/b/c");
戻り値:true
新しいディレクトリが作成された場合、それ以外の場合は false
.
これが私のコード例です (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++17 以降では、標準ヘッダー <filesystem>
があります。 withfunctionstd::filesystem::create_directories
ただし、C++ 標準関数には POSIX 固有の明示的な許可 (モード) 引数がありません。
ただし、C++ コンパイラでコンパイルできる 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 */
マクロ STRDUP()
と FREE()
strdup()
のエラーチェック バージョンです。 と free()
、emalloc.h
で宣言 (そしてemalloc.c
で実装 と estrdup.c
)."sysstat.h"
ヘッダーは <sys/stat.h>
の壊れたバージョンを扱います <sys/stat.h>
に置き換えることができます 最近の Unix システムでは (しかし 1990 年には多くの問題がありました)、"mkpath.h"
mkpath()
を宣言します .
v1.12 (回答の元のバージョン) と v1.13 (回答の修正版) の間の変更は、EEXIST
のテストでした。 do_mkdir()
で これは必要に応じて Switch によって指摘されました — ありがとう、Switch。テスト コードはアップグレードされ、MacBookPro (2.3GHz Intel Core i7、Mac OS X 10.7.4 を実行) で問題を再現しました。リビジョン (ただし、テストではバグの存在のみが示され、バグがないことは示されません)。示されているコードは現在 v1.16 です。 v1.13 以降、表面的または管理上の変更が行われています (mkpath.h
を使用するなど)。 jlss.h
の代わりに andinclude <unistd.h>
"sysstat.h"
と主張するのは合理的です。 <sys/stat.h>
に置き換える必要があります 異常に反抗的なシステムでない限り.
(ここに、帰属を伴うあらゆる目的でこのコードを使用する許可が与えられます。)
このコードは、GitHub の SOQ (Stack Overflow Questions) リポジトリでファイル mkpath.c
として入手できます。 そしてmkpath.h
(など) src/so-0067-5039 サブディレクトリにあります。