Как мне рекурсивно создать папку в Win32? - PullRequest
32 голосов
/ 07 октября 2009

Я пытаюсь создать функцию, которая берет имя каталога (C:\foo\bar, или ..\foo\bar\..\baz, или \\someserver\foo\bar) и создает каталоги по мере необходимости, чтобы был создан весь путь.

Я пытаюсь реализовать это довольно наивно, и это похоже на кошмар обработки строк. Существует / против \, есть особый случай сетевых ресурсов, которые начинаются с \\ (также вы не можете попытаться выполнить mkdir () на первых двух уровнях пути, которые являются именем компьютера и именем общего ресурса) и существует бессмыслица типа \.\, которая может существовать в пути.

Существует ли простой способ сделать это в C ++?

Ответы [ 13 ]

0 голосов
/ 23 апреля 2015

Вот мой пример кода (скопировано с Как я могу создать дерево каталогов в 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;
}

Использование:

d:\Work\c++\make_path> makePath 1/2 folderA/folderB/folderC
creating 1/2 ... OK
creating folderA/folderB/folderC ... OK
0 голосов
/ 07 октября 2009

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


Вы можете использовать старый добрый mkdir для этого. Просто беги

system("mkdir " + strPath);

и все готово.

Ну, почти. Есть еще случаи, о которых вам нужно позаботиться, такие как общие сетевые ресурсы (которые могут не работать) и обратные слеши. Но при использовании относительно безопасных путей вы можете использовать эту более короткую форму.

Другая вещь, которая может оказаться полезной для избавления от возможной неприятности, - это _fullpath () , которая преобразует данный путь в полный и чистый. Зная, что у вас есть чистый путь, у вас не должно возникнуть проблем с написанием довольно тривиальной рекурсивной функции, которая будет создавать папки одну за другой, даже при работе с путями UNC.

0 голосов
/ 07 октября 2009

С http://www.cplusplus.com/reference/string/string/find_last_of/:

// string::find_last_of
#include <iostream>
#include <string>
using namespace std;

void SplitFilename (const string& str)
{
  size_t found;
  cout << "Splitting: " << str << endl;
  found=str.find_last_of("/\\");
  cout << " folder: " << str.substr(0,found) << endl;
  cout << " file: " << str.substr(found+1) << endl;
}

int main ()
{
  string str1 ("/usr/bin/man");
  string str2 ("c:\\windows\\winhelp.exe");

  SplitFilename (str1);
  SplitFilename (str2);

  return 0;

Это должно дать вам представление о том, как обращаться со строкой пути. Затем, после этого, все, что вам нужно сделать, это перебрать пути, начиная с диска до самой глубокой папки. Проверьте, существует ли папка, и если нет, создайте ее.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...