Quero uma maneira fácil de criar vários diretórios em C ++ / Linux.
Por exemplo, quero salvar um arquivo lola.file no diretório:
/tmp/a/b/c
mas se os diretórios não estiverem lá, quero que sejam criados automaticamente. Um exemplo prático seria perfeito.
Respostas:
Com C ++ 17 ou posterior, existe o cabeçalho padrão
<filesystem>
com funçãostd::filesystem::create_directories
que deve ser usado em programas C ++ modernos. No entanto, as funções padrão C ++ não têm o argumento de permissões explícitas específicas de POSIX (modo).No entanto, aqui está uma função C que pode ser compilada com compiladores C ++.
As macros
STRDUP()
eFREE()
são versões de verificação de erros destrdup()
efree()
, declaradas ememalloc.h
(e implementadas ememalloc.c
eestrdup.c
). O"sysstat.h"
cabeçalho lida com versões quebradas<sys/stat.h>
e pode ser substituído por<sys/stat.h>
em sistemas Unix modernos (mas havia muitos problemas em 1990). E"mkpath.h"
declaramkpath()
.A mudança entre v1.12 (versão original da resposta) e v1.13 (versão corrigida da resposta) foi o teste para
EEXIST
emdo_mkdir()
. Isso foi apontado como necessário por Switch - obrigado, Switch. O código de teste foi atualizado e reproduziu o problema em um MacBook Pro (2,3 GHz Intel Core i7, executando Mac OS X 10.7.4) e sugere que o problema foi corrigido na revisão (mas o teste só pode mostrar a presença de bugs , nunca sua ausência). O código mostrado agora é v1.16; houve mudanças cosméticas ou administrativas feitas desde v1.13 (como usar emmkpath.h
vez dejlss.h
e incluir<unistd.h>
incondicionalmente apenas no código de teste). É razoável argumentar que"sysstat.h"
deve ser substituído por, a<sys/stat.h>
menos que você tenha um sistema invulgarmente recalcitrante.(Você recebe permissão para usar este código para qualquer finalidade com atribuição.)
Este código está disponível em meu repositório SOQ (Stack Overflow Questions) no GitHub como arquivos
mkpath.c
emkpath.h
(etc.) no subdiretório src / so-0067-5039 .fonte
if (errno != EEXIST) { status = -1; }
quando o mkdir falhar.stat()
antesmkdir()
; é um problema TOCTOU (tempo de verificação, tempo de uso). Tentei acertar o bug com um script de shell executando 13 processos em segundo plano, criando o mesmo caminho de 29 elementos, e não consegui acertá-lo. Então eu hackeei o programa de teste para fazer o fork 20 vezes e fiz cada criança tentar, e isso acertou o bug. O código fixo teráif (mkdir(path, mode) != 0 && errno != EEXIST) status = -1;
. Isso não mostra o bug.jlss.h
,emalloc.h
), não bibliotecas. No entanto, o código está disponível em meus SOQ (Perguntas Stack Overflow) repositório no GitHub como arquivosjlss.h
,emalloc.c
eemalloc.h
no src / libsoq sub-diretório. Você vai precisarposixver.h
também, e alguns outros (debug.h
,stderr.c
,stderr.h
- eu acho que é isso, mas o que você precisa todos devem estar nesse diretório).Fácil com Boost.Filesystem:
create_directories
Retorna:
true
se um novo diretório foi criado, caso contráriofalse
.fonte
The <filesystem> header is not part of C++11; it is a proposal for C++ TR2 based on the Boost.Filesystem library. Visual C++ 2012 includes an implementation of the proposed library.
é o caminho mais curto que posso imaginar (em termos de comprimento de código, não necessariamente tempo de execução).
Não é multiplataforma, mas funcionará no Linux.
fonte
A partir daqui . Você pode ter que fazer mkdirs separados para / tmp, / tmp / a, / tmp / a / b / e então / tmp / a / b / c porque não há um equivalente do sinalizador -p na API C. Certifique-se de ignorar o erro EEXISTS enquanto estiver fazendo os de nível superior.
fonte
("/tmp/",...)
,("/tmp/a/",...)
,("/tmp/a/b/",...)
,("/tmp/a/b/c/",...)
Aqui está meu exemplo de código (funciona para Windows e Linux):
Uso:
fonte
stat
(relacionado a__STDC__
) sem necessidade de teste de pré-compilador.Deve-se notar que a partir da interface do sistema de arquivos C ++ 17 faz parte da biblioteca padrão. Isso significa que é possível ter o seguinte para criar diretórios:
Mais informações aqui: https://en.cppreference.com/w/cpp/filesystem/create_directory
Além disso, com o gcc, é necessário "-std = c ++ 17" para CFLAGS. E "-lstdc ++ fs" para LDLIBS. O último potencialmente não será necessário no futuro.
fonte
Isso é semelhante ao anterior, mas funciona para a frente através da string em vez de recursivamente para trás. Deixa errno com o valor correto para a última falha. Se houver uma barra inicial, haverá um tempo extra no loop que poderia ter sido evitado por meio de um find_first_of () fora do loop ou detectando o / e definindo pre em 1. A eficiência é a mesma se formos configurados por um primeiro loop ou uma chamada de pré-loop, e a complexidade seria (ligeiramente) maior ao usar a chamada de pré-loop.
fonte
Você disse "C ++", mas todos aqui parecem estar pensando "Bash shell".
Verifique o código-fonte do gnu
mkdir
; então você pode ver como implementar os comandos do shell em C ++.fonte
fonte
Então, eu preciso
mkdirp()
hoje e achei as soluções nesta página muito complicadas. Portanto, escrevi um trecho bastante curto, que pode ser facilmente copiado para outras pessoas que se depararem com este tópico e me perguntem por que precisamos de tantas linhas de código.mkdirp.h
mkdirp.cpp
Se você não gosta de lançar const e modificar temporariamente a string, basta fazer um
strdup()
efree()
depois.fonte
Uma vez que esta postagem está no topo do ranking do Google para "Criar árvore de diretórios", postarei uma resposta que funcionará para Windows - funcionará usando a API Win32 compilada para UNICODE ou MBCS. Isso é transferido do código de Mark acima.
Como estamos trabalhando com o Windows, os separadores de diretório são barras invertidas, não barras normais. Se você preferir barras, mude
'\\'
para'/'
Funcionará com:
e
(ou seja: não precisa de barra final, então você não precisa verificar).
Antes de dizer "Basta usar SHCreateDirectoryEx () no Windows", observe que SHCreateDirectoryEx () está obsoleto e pode ser removido a qualquer momento de versões futuras do Windows.
fonte
c:\this\is\a/mixed/path\of\slashes
Normalmente as barras do Windows são barras invertidas. O que deve acontecer é que o chamador deve limpar o caminho e garantir que todas as barras estejam corretas antes de chamar esse método.Eu sei que é uma pergunta antiga, mas aparece no topo dos resultados de pesquisa do Google e as respostas fornecidas aqui não estão realmente em C ++ ou são um pouco complicadas.
Observe que no meu exemplo, createDirTree () é muito simples porque todo o trabalho pesado (verificação de erros, validação de caminho) precisa ser feito por createDir () de qualquer maneira. Além disso, createDir () deve retornar true se o diretório já existir ou se tudo isso não funcionar.
Veja como eu faria isso em C ++:
É claro que a função createDir () será específica do sistema e já existem exemplos suficientes em outras respostas de como escrevê-la para Linux, então decidi pular.
fonte
Se dir não existir, crie-o:
fonte
Muitas abordagens foram descritas aqui, mas a maioria delas precisa de codificação rígida de seu caminho em seu código. Existe uma solução fácil para esse problema, usando QDir e QFileInfo, duas classes do framework Qt. Como você já está no ambiente Linux, deve ser fácil usar o Qt.
Certifique-se de ter acesso de gravação a esse caminho.
fonte
fonte
-p
opção é o que procuro. Obrigado!Aqui está a função recursiva C / C ++ que usa
dirname()
para percorrer de baixo para cima a árvore de diretórios. Ele irá parar assim que encontrar um ancestral existente.fonte
Os outros deram a resposta certa, mas pensei em demonstrar outra coisa legal que você pode fazer:
Irá criar os seguintes caminhos:
As chaves permitem que você crie vários diretórios de uma vez no mesmo nível da hierarquia, enquanto a
-p
opção significa "criar diretórios pais conforme necessário".fonte