2009-10-04 5 views
2

Я нашел много примеров CreateDirectory рекурсивно, но не тот, который я искал.Рекурсивный CreateDirectory

здесь спецификация

Учитывая вход

  1. \\ сервер \ папка \ аа \ бб \ куб.см
  2. с: \ аа \ бб \ куб.см

с использованием помощника API

CreateDirectory (char * path) 
returns true, if successful 
else 
FALSE 

Состояние: Там не должно быть никакого синтаксического анализа, чтобы различать, является ли путь локальным или общим ресурсом сервера.

Написать подпрограмму в C или C++

+1

ли это вопрос домашней работы? (Это не проблема, если это так) –

+2

Если это не удается, не хотите ли вы узнать (и сообщить вызывающему), почему это не удалось? Причинами сбоев являются: 'no permission',' файл с тем же именем уже существует', 'no space on disk'. – pmg

+0

Дубликат http://stackoverflow.com/q/1530760/103167, за исключением того, что не указано, что 'CreateDirectory' означает функцию Win32 (хотя большинство ответов предполагало, что это так) –

ответ

0

Просто пройти через каждый уровень каталогов в пути, начиная от корня, который пытается создать следующий уровень.

Если какой-либо из вызовов CreateDirectory терпит неудачу, вы можете выйти рано, вам удастся, если вы дойдете до конца пути без сбоя.

Это предполагает, что вызов CreateDirectory по уже существующему пути не имеет вредных эффектов.

+0

Единственное, что нужно посмотреть, это разные ошибки для «Отсутствие разрешения» vs 'directory уже существует ». Попытка создать существующий каталог будет просто терпеть неудачу (если вы не станете антикварной версией NFS, когда могут произойти всевозможные вещи с нечетным шаром). –

1

Полностью хак и небезопасны, и ничего вы когда-нибудь на самом деле хотите сделать в производстве код, но ...

Внимание: здесь будет код, который был набран в браузере:

int createDirectory(const char * path) { 
    char * buffer = malloc((strlen(path) + 10) * sizeof(char)); 
    sprintf(buffer, "mkdir -p %s", path); 
    int result = system(buffer); 
    free(buffer); 
    return result; 
} 
+1

Есть еще худшие способы сделать это. Однажды несколько десятилетий назад это было необходимо: в версии 7 Unix «mkdir» была корневой программой SUID и не было системного вызова 'mkdir()' (но также не было опции '-p' для' mkdir'). –

0

Интересно не требование разбора имени пути для имен серверов, поскольку, по-видимому, требуется разглашение для /.

Возможно, идея состоит в том, чтобы не создавать хакерские выражения для потенциально сложного синтаксиса для хостов и точек монтирования, которые могут иметь на некоторых системах разработку кодированных учетных данных.

Если это домашняя работа, я могу отдать алгоритм, который вы должны придумать, но мне приходит в голову, что одним из способов удовлетворения этих требований является попытка попробовать, выполнив mkdir полный путь. Если это не удается, обрезайте последний каталог и повторите попытку, если это не удастся, отрежьте другое и повторите попытку ... В конце концов вам нужно добраться до корневого каталога, не понимая синтаксиса сервера, а затем вам нужно будет запустить добавление компонентов пути назад и создание поддиретов по одному.

1

Как насчет использования MakeSureDirectoryPathExists()?

+0

* «Эта функция не поддерживает строки Unicode. Чтобы указать путь Unicode, используйте функцию ** SHCreateDirectoryEx **.» * –

2

Это может быть именно то, что вы хотите. Он не пытается выполнять синтаксический разбор, чтобы различать, является ли путь локальным или общим ресурсом сервера.

bool TryCreateDirectory(char *path){ 
    char *p; 
    bool b; 

    if(
     !(b=CreateDirectory(path)) 
     && 
     !(b=NULL==(p=strrchr(path, '\\'))) 
     ){ 
     size_t i; 

     (p=strncpy((char *)malloc(1+i), path, i=p-path))[i]='\0'; 
     b=TryCreateDirectory(p); 
     free(p); 
     b=b?CreateDirectory(path):false; 
    } 

    return b; 
} 

Алгоритм достаточно прост, просто передать строку высшего уровня директории рекурсивно при создании текущего уровня каталога не удается до одного успеха или нет более высокий уровень. Когда внутренний вызов возвращается с успехом, создайте текущий. Этот метод не анализирует, чтобы определить локальный или серверный сервер, это согласно CreateDirectory. В WINAPI CreateDirectory никогда не позволит вам создавать «c:» или «\», когда путь достигнет этого уровня, метод скоро попадает в вызов его self с path = "", и это тоже не сработает. Именно по этой причине Microsoft определяет правило именования файлов, подобное этому, для совместимости правила пути DOS и упрощения усилий по кодированию.

+2

+1 для алгоритма, но ваш стиль кодировки ужасен. И BTW, с MinGW (= gcc), вы должны вычислить 'i' вне вызова' strncpy'. – Seki

0
std::pair<bool, unsigned long> CreateDirectory(std::basic_string<_TCHAR> path) 
{ 
    _ASSERT(!path.empty()); 
    typedef std::basic_string<_TCHAR> tstring; 

    tstring::size_type pos = 0; 

    while ((pos = path.find_first_of(_T("\\/"), pos + 1)) != tstring::npos) 
    { 
     ::CreateDirectory(path.substr(0, pos + 1).c_str(), nullptr); 
    } 

    if ((pos = path.find_first_of(_T("\\/"), path.length() - 1)) == tstring::npos) 
    { 
     path.append(_T("\\")); 
    } 

    ::CreateDirectory(path.c_str(), nullptr); 

    return std::make_pair(
     ::GetFileAttributes(path.c_str()) != INVALID_FILE_ATTRIBUTES, 
     ::GetLastError() 
     ); 
} 
+1

Рекурсии не требуется. ПРИМЕЧАНИЕ: 'C: \ mydir \ mydir.txt \ mydir.pdf \ here' является допустимым путем. – jasnmoore

4

Я думаю, что это довольно легко ... вот версия, которая работает в любой версии Windows:

unsigned int pos = 0; 
do 
{ 
    pos = path.find_first_of("\\/", pos + 1); 
    CreateDirectory(path.substr(0, pos).c_str(), NULL); 
} while (pos != std::string::npos); 

Unicode:

pos = path.find_first_of(L"\\/", pos + 1); 

С уважением,

+0

Примечание: pos должен быть подписанным int, а не беззнаковым int, или результат npos будет переполняться, и вы будете застревать в бесконечном цикле. –

0
void createFolders(const std::string &s, char delim) { 
std::stringstream ss(s); 
std::string item; 
char combinedName[50]={'\0'}; 
while (std::getline(ss, item, delim)) { 
    sprintf(combinedName,"%s%s%c",combinedName,item.c_str(),delim);   
    cout<<combinedName<<endl; 
    struct stat st = {0}; 
    if (stat(combinedName,&st)==-1) 
    { 
      #if REDHAT 
        mkdir(combinedName,0777); 
      #else 
         CreateDirectory(combinedName,NULL); 
      #endif 
    } 
} 
} 
+0

Не могли бы вы добавить текст, чтобы объяснить свой ответ? – Kmeixner

+0

createFloders ("a/b/c/d/e", '/'); –

Смежные вопросы