C ++ / Linux에서 디렉토리 트리를 어떻게 만들 수 있습니까?
C ++ / Linux에서 여러 디렉터리를 쉽게 만드는 방법을 원합니다.
예를 들어 lola.file 파일을 디렉토리에 저장하고 싶습니다.
/tmp/a/b/c
그러나 디렉토리가 없으면 자동으로 생성되기를 원합니다. 작동하는 예가 완벽합니다.
다음은 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 = '\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>
/*
** 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>
현대적인 유닉스 시스템 (그러나 많은 문제가 1990 년에 다시 있었다). 그리고 "jlss.h"
선언합니다 mkpath()
.
(이전)를 v1.12과 v1.13 (위) 사이의 변화에 대한 시험이다 EEXIST
에서 do_mkdir()
. Switch가 필요하다고 지적했습니다 . 감사합니다. Switch. 테스트 코드가 업그레이드되어 MacBook Pro (2.3GHz Intel Core i7, Mac OS X 10.7.4 실행)에서 문제가 재현되었으며 수정 버전에서 문제가 수정되었음을 제안합니다 (그러나 테스트는 버그의 존재만을 보여줄 수 있음) , 절대 부재).
(귀하는 어떤 목적 으로든이 코드를 사용할 수있는 권한을 부여 받았습니다.)
Boost.Filesystem으로 쉽게 : create_directories
#include <boost/filesystem.hpp>
//...
boost::filesystem::create_directories("/tmp/a/b/c");
반환 값 : true
새 디렉토리가 생성 된 경우, 그렇지 않은 경우 false
.
system("mkdir -p /tmp/a/b/c")
내가 생각할 수있는 가장 짧은 방법입니다 (반드시 실행 시간이 아니라 코드 길이 측면에서).
크로스 플랫폼은 아니지만 Linux에서 작동합니다.
다음은 코드 예제입니다 (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
#include <sys/types.h>
#include <sys/stat.h>
int status;
...
status = mkdir("/tmp/a/b/c", S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
에서 여기 . / tmp, / tmp / a, / tmp / a / b / 및 / tmp / a / b / c에 대해 별도의 mkdirs를 수행해야 할 수 있습니다. C api에는 -p 플래그와 동일한 것이 없기 때문입니다. 상위 레벨 작업을 수행하는 동안 EEXISTS errno를 반드시 무시하십시오.
이것은 이전과 유사하지만 재귀 적으로 역방향이 아닌 문자열을 통해 앞으로 작동합니다. 마지막 실패에 대한 올바른 값으로 errno를 남깁니다. 선행 슬래시가있는 경우 루프 외부의 find_first_of () 하나를 통해 또는 선행 /를 감지하고 pre를 1로 설정하여 피할 수 있었던 루프를 통해 추가 시간이 있습니다. 효율성은 a에 의해 설정 되든 동일합니다. 첫 번째 루프 또는 사전 루프 호출이며 사전 루프 호출을 사용할 때 복잡성이 (약간) 높아집니다.
#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 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';
}
"C ++"라고 하셨는데 여기 계신 분들은 모두 "Bash shell"을 생각하시는 것 같습니다.
gnu에 대한 소스 코드를 확인하십시오 mkdir
. 그러면 C ++에서 쉘 명령을 구현하는 방법을 볼 수 있습니다.
C ++ 17 파일 시스템 인터페이스에서 시작하는 것은 표준 라이브러리의 일부입니다. 이것은 디렉토리를 생성하기 위해 다음을 가질 수 있음을 의미합니다.
#include <filesystem>
std::filesystem::create_directories("/a/b/c/d")
자세한 정보 : https://en.cppreference.com/w/cpp/filesystem/create_directory
또한 gcc를 사용하면 CFLAGS에 "-std = c ++ 17"이 필요합니다. 그리고 "-lstdc ++ fs"는 LDLIBS로. 후자는 잠재적으로 미래에 필요하지 않을 것입니다.
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;
}
나는 그것이 오래된 질문이라는 것을 알고 있지만 그것은 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 () 함수는 시스템에 따라 다르며 다른 답변에는 이미 리눅스 용으로 작성하는 방법에 대한 충분한 예제가 있으므로 건너 뛰기로 결정했습니다.
그래서 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_H
mkdirp.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 != '\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;
}
const 캐스팅을 좋아하지 않고 일시적으로 문자열을 수정하는 것이 마음에 들지 않으면 a strdup()
를 수행 free()
하고 나중에 수행하십시오.
이 게시물은 "Create Directory Tree"에 대해 Google에서 높은 순위를 차지하고 있으므로 Windows에서 작동하는 답변을 게시 할 것입니다. 이것은 UNICODE 또는 MBCS 용으로 컴파일 된 Win32 API를 사용하여 작동합니다. 이것은 위의 Mark의 코드에서 이식되었습니다.
이것이 우리가 작업하는 Windows이기 때문에 디렉토리 구분 기호는 슬래시가 아니라 백 슬래시입니다. 슬래시를 사용하려면 다음 '\\'
으로 변경하십시오 .'/'
다음과 함께 작동합니다.
c:\foo\bar\hello\world
과
c:\foo\bar\hellp\world\
(예 : 후행 슬래시가 필요하지 않으므로 확인할 필요가 없습니다.)
" Windows에서 SHCreateDirectoryEx () 를 사용하십시오"라고 말하기 전에 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;
}
dir이 없으면 작성하십시오.
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
다른 사람들은 당신에게 정답을 얻었지만 나는 당신이 할 수있는 또 다른 깔끔한 것을 보여줄 것이라고 생각했습니다.
mkdir -p /tmp/a/{b,c}/d
다음 경로를 생성합니다.
/tmp/a/b/d
/tmp/a/c/d
중괄호를 사용하면 동일한 계층 수준에서 한 번에 여러 디렉터리를 만들 수 있지만 -p
옵션은 "필요에 따라 부모 디렉터리 만들기"를 의미합니다.
참고 URL : https://stackoverflow.com/questions/675039/how-can-i-create-directory-tree-in-c-linux
'program tip' 카테고리의 다른 글
보기 위해 프로세스 출력에 첨부 (0) | 2020.08.17 |
---|---|
XmlDocument에서 줄 바꿈을 사용하여 들여 쓰기 된 XML을 얻는 가장 간단한 방법은 무엇입니까? (0) | 2020.08.17 |
스위치 문과 함께 열거 형을 사용하는 Java (0) | 2020.08.16 |
PDO를 사용하여 NULL 값을 어떻게 삽입합니까? (0) | 2020.08.16 |
UUID 최대 문자 길이 (0) | 2020.08.16 |