O Node.js cria uma pasta ou usa os existentes

186

Eu já li a documentação do Node.js e, a menos que tenha perdido algo, ele não informa o que os parâmetros contêm em determinadas operações, em particular fs.mkdir(). Como você pode ver na documentação, não é muito.

Atualmente, eu tenho esse código, que tenta criar uma pasta ou usar uma existente:

fs.mkdir(path,function(e){
    if(!e || (e && e.code === 'EEXIST')){
        //do something with contents
    } else {
        //debug
        console.log(e);
    }
});

Mas eu me pergunto: esse é o caminho certo para fazer isso? A verificação do código é EEXISTa maneira correta de saber se a pasta já existe? Eu sei que posso fazer fs.stat()antes de criar o diretório, mas isso já seria duas ocorrências no sistema de arquivos.

Em segundo lugar, existe uma documentação completa ou pelo menos mais detalhada do Node.js que contém detalhes sobre quais objetos de erro contêm, quais parâmetros significam etc.

Joseph
fonte
31
Nitpick pequeno, mas se livrar do e &&. Se !efalhar, você sabe que eé verdade.
Eu odeio preguiçoso

Respostas:

236

Uma boa maneira de fazer isso é usar o módulo mkdirp .

$ npm install mkdirp

Use-o para executar a função que requer o diretório. O retorno de chamada é chamado depois que o caminho é criado ou se o caminho já existe. O erro errserá definido se o mkdirp falhar ao criar o caminho do diretório.

var mkdirp = require('mkdirp');
mkdirp('/tmp/some/path/foo', function(err) { 

    // path exists unless there was an error

});
Teemu Ikonen
fonte
3
Parece-me que a resposta correta (leia-se 'sem adição de dependência') seria a mais baixa, por @Raugaral, usando fs.exists(Sync).
Ricardo Pedroni
@meawoppl, é 'makedirectory'p. O 'p' é desconhecido.
18715 Andrew Andrew
4
@RicardoPedroni A maneira correta é usar um módulo. Os módulos geralmente tentam de todo o coração resolver um problema e geralmente são mantidos. Você pode atualizá-los facilmente com o npm. Além disso, você deve evitar especificamente o uso de fs.exists [Sync], pois seu uso implica condições de corrida.
1j01 12/12/2015
16
@ 1j01 Não acredito que a maneira correta seja usar um módulo se a plataforma suportar nativamente a operação. Essa é uma estrada para o caos. Eu tenho que concordar que existem respostas melhores do ponto de vista técnico.
c ..
2
@ 1j01 Além disso, o uso das operações de sincronização implica condições de corrida, porque o uso delas é uma resolução para elas.
c ..
193

Editar: como essa resposta é muito popular, eu a atualizei para refletir as práticas atualizadas.

Nó> = 10

A nova { recursive: true }opção do Node fsagora permite isso de forma nativa. Esta opção imita o comportamento do UNIX mkdir -p. Ele recursivamente garantirá que todas as partes do caminho existam e não emitirá um erro se houver alguma.

(Nota: ele ainda pode gerar erros como EPERMou EACCESS, portanto, melhor ainda envolvê-lo try {} catch (e) {}se sua implementação for suscetível a ele.)

Versão síncrona.

fs.mkdirSync(dirpath, { recursive: true })

Versão assíncrona

await fs.promises.mkdir(dirpath, { recursive: true })

Versões mais antigas do nó

Usando a try {} catch (err) {}, você pode conseguir isso com muita graciosidade sem encontrar uma condição de corrida.

Para evitar o tempo morto entre a verificação da existência e a criação do diretório, simplesmente tentamos criá-lo diretamente e desconsideramos o erro, se houver EEXIST(o diretório já existe).

Se o erro não for EEXIST, no entanto, devemos gerar um erro, porque poderíamos estar lidando com algo como um EPERMouEACCES

function ensureDirSync (dirpath) {
  try {
    return fs.mkdirSync(dirpath)
  } catch (err) {
    if (err.code !== 'EEXIST') throw err
  }
}

Para mkdir -p-como comportamento recursivo, por exemplo ./a/b/c, você teria que chamá-lo em todas as partes do dirpath, por exemplo ./a, ./a/b,.a/b/c

Christophe Marois
fonte
var fs = Npm.require ('fs'); var dir = process.env.PWD + '/ files / users /' + this.userId + '/'; tente {fs.mkdirSync (dir); } catch (e) {if (e.code! = 'EEXIST') throw e; }
Aaron
Eu tentei o seu código, crie um script js que use a criação do catálogo como este: mkdirpSync (path.join (__ dirname, 'primeiro', 'segundo', 'terceiro', 'ololol', 'funciona')); Mas obtive este erro: $ node 1.js fs.js: 747 retornam binding.mkdir (pathModule._makeLong (path), ^ Error: EPERM, operação não permitida 'C: \' em Error (native) em Object.fs. mkdirSync (fs.js: 747: 18) em mkdirpSync (C: \ Usuários \ MAXIM \ Desktop \ test \ 1.js: 15: 8) no Objeto. <anônimo> (C: \ Usuários \ MAXIM \ Desktop \ test \ 1.js: 19: 1) ... você poderia sugerir que poderia estar errado usado em janelas, obviamente :)?
Alendorff
EPERM parece ser um problema de permissão, de modo que o script seria paraíso quebrado execução de qualquer maneira
Christophe Marois
Eu acho que seria melhor: var mkdirpSync = function (dirpath) {var parts = dirpath.split (path.sep); for (var i = 1; i <= parts.length; i ++) {try {fs.mkdirSync (path.join.apply (null, parts.slice (0, i))); } catch (erro) {if (error.code! = 'EEXIST') {throw error; }}}}
Manish
1
Aviso: Não funciona se o caminho começa com um /
acemtp
62

Se você deseja um liner rápido e sujo, use o seguinte:

fs.existsSync("directory") || fs.mkdirSync("directory");
marekventur
fonte
1
fs.existsestá obsoleto: nodejs.org/api/fs.html#fs_fs_exists_path_callback
adius
7
O fs.existsSync (...) não está obsoleto, portanto, esta resposta parece estar correta.
Dan Haywood
Atenção! Não vai funcionar para "dir / foo / bar", ou seja não possui o recurso bandeira mkdir -p
Karl Pokus
Isso também tem uma condição de corrida
Evert
26

O node.js documenta fs.mkdirbasicamente adira à página de manual do Linux paramkdir(2) . Isso indica que EEXISTtambém será indicado se o caminho existe, mas não é um diretório que cria uma caixa de canto estranha se você seguir esta rota.

Pode ser melhor ligar para fs.stat se o caminho existe e se é um diretório em uma única chamada. Pois (o que eu suponho) é o caso normal em que o diretório já existe, é apenas um único hit no sistema de arquivos.

Esses fsmétodos de módulo são invólucros finos em torno das APIs C nativas, portanto você deve verificar as páginas de manual mencionadas nos documentos node.js. para obter detalhes.

JohnnyHK
fonte
19
Ligar statantes mkdirtem o potencial para uma condição de corrida - tenha isso em mente.
precisa
24

Você pode usar isto:

if(!fs.existsSync("directory")){
    fs.mkdirSync("directory", 0766, function(err){
        if(err){
            console.log(err);
            // echo the result back
            response.send("ERROR! Can't make the directory! \n");
        }
    });
}
Raugaral
fonte
1
-1. Eu não acredito que isso funcione, statSynclançará um erro se a entidade não existir, travando o código. Você precisa agrupar isso em um try/catchbloco.
Chris Foster
2
Desculpe estou errado. alterar "statSync" para "existeSync"
Raugaral 4/14/14
5
De acordo com nodejs.org/api/fs.html#fs_fs_mkdirsync_path_mode a variante de sincronização de mkdir não aceita uma chamada de retorno
danwellman
1
De acordo com nodejs.org/api/fs.html#fs_fs_existssync_path , fs.existsSync()e fs.exists()será substituído.
pau.moreno
7

Proponho uma solução sem módulos (os módulos acumulados nunca são recomendados para manutenção, especialmente para pequenas funções que podem ser escritas em poucas linhas ...):

ÚLTIMA ATUALIZAÇÃO :

Na v10.12.0, as opções recursivas da implementação do NodeJS:

// Create recursive folder
fs.mkdir('my/new/folder/create', { recursive: true }, (err) => { if (err) throw err; });

ATUALIZAÇÃO:

// Get modules node
const fs   = require('fs');
const path = require('path');

// Create 
function mkdirpath(dirPath)
{
    if(!fs.accessSync(dirPath, fs.constants.R_OK | fs.constants.W_OK))
    {
        try
        {
            fs.mkdirSync(dirPath);
        }
        catch(e)
        {
            mkdirpath(path.dirname(dirPath));
            mkdirpath(dirPath);
        }
    }
}

// Create folder path
mkdirpath('my/new/folder/create');
Liberateur
fonte
fs.exists()foi descontinuado no nó v9. use em fs.access()vez disso. (retornos undefinedse o arquivo existir, caso contrário gera um erro ENOENT)
chharvey
Sem nenhum pacote npm, está funcionando. É um código valioso. Obrigado
Karthik Sridharan
Este é muito melhor para criar uma pasta no caminho longo existente;) Obrigado, cara.
Tsung Goh
1
Que tal fs.mkdirSync('my/new/folder/create', {recursive: true})?
Saitho 10/03/19
Obrigado ! Eu atualizo minha postagem para ajudar outras pessoas. O nó 10.12.0 era muito recente.
Liberateur
4

Você também pode usar fs-extra , que fornece muitas operações de arquivos usadas com frequência.

Código de amostra:

var fs = require('fs-extra')

fs.mkdirs('/tmp/some/long/path/that/prob/doesnt/exist', function (err) {
  if (err) return console.error(err)
  console.log("success!")
})

fs.mkdirsSync('/tmp/another/path')

docs aqui: https://github.com/jprichardson/node-fs-extra#mkdirsdir-callback

Geng Jiawen
fonte
4

Aqui está o código ES6 que eu uso para criar um diretório (quando ele não existe):

const fs = require('fs');
const path = require('path');

function createDirectory(directoryPath) {
  const directory = path.normalize(directoryPath);

  return new Promise((resolve, reject) => {
    fs.stat(directory, (error) => {
      if (error) {
        if (error.code === 'ENOENT') {
          fs.mkdir(directory, (error) => {
            if (error) {
              reject(error);
            } else {
              resolve(directory);
            }
          });
        } else {
          reject(error);
        }
      } else {
        resolve(directory);
      }
    });
  });
}

const directoryPath = `${__dirname}/test`;

createDirectory(directoryPath).then((path) => {
  console.log(`Successfully created directory: '${path}'`);
}).catch((error) => {
  console.log(`Problem creating directory: ${error.message}`)
});

Nota:

  • No início da createDirectoryfunção, eu normalizar o caminho para a garantia de que o tipo seperator caminho do sistema operacional será usado de forma consistente (por exemplo, isso vai se transformar C:\directory/testemC:\directory\test (quando estar no Windows)
  • fs.existsestá obsoleto , é por isso que eu usofs.stat para verificar se o diretório já existe
  • Se um diretório não existir, o código de erro será ENOENT( E rror NO ENT ry)
  • O diretório em si será criado usando fs.mkdir
  • Prefiro a função assíncrona do fs.mkdirque a contraparte de bloqueio fs.mkdirSynce, devido ao empacotamento Promise, será garantido que o caminho do diretório seja retornado somente após o diretório ter sido criado com êxito.
Benny Neugebauer
fonte
Obrigado por uma solução limpa que não envolve módulos desnecessários. Funcionou perfeitamente para mim. Eu gostaria que houvesse mais respostas como essa!
Ken Lyon
3

É melhor não contar os hits do sistema de arquivos enquanto codifica em Javascript, na minha opinião. No entanto, (1) stat& mkdire (2) mkdire cheque (ou descartar) o código de erro, ambos os caminhos são caminhos certos para fazer o que quiser.

Chul-Woong Yang
fonte
-1, não vejo como verificar ou descartar as duas maneiras certas de fazê-lo. Isso é praticamente uma não resposta.
Matt Bola
É uma boa maneira de mkdir um diretório ou usar um existente. Não vejo por que você não vê. A verificação do código de erro é educada, e descartar o código de erro é apenas uma boa. você não concorda?
Chul-Woong Yang
1
Talvez esse seja um problema de barreira do idioma, mas eu li isso como não respondendo à pergunta que o OP está fazendo.
Matt Bola
Entendo qual é o seu ponto. No entanto, acredito que existem muitas maneiras de fazer as coisas corretamente. Obrigado.
Chul-Woong Yang
2

crie um diretório de nome dinâmico para cada usuário ... use este código

***suppose email contain user mail address***

var filessystem = require('fs');
var dir = './public/uploads/'+email;

if (!filessystem.existsSync(dir)){
  filessystem.mkdirSync(dir);

}else
{
    console.log("Directory already exist");
}
Adiii
fonte
1

Você pode fazer tudo isso com o módulo Sistema de arquivos.

const
  fs = require('fs'),
  dirPath = `path/to/dir`

// Check if directory exists.
fs.access(dirPath, fs.constants.F_OK, (err)=>{
  if (err){
    // Create directory if directory does not exist.
    fs.mkdir(dirPath, {recursive:true}, (err)=>{
      if (err) console.log(`Error creating directory: ${err}`)
      else console.log('Directory created successfully.')
    })
  }
  // Directory now exists.
})

Você realmente nem precisa verificar se o diretório existe. O código a seguir também garante que o diretório já exista ou seja criado.

const
  fs = require('fs'),
  dirPath = `path/to/dir`

// Create directory if directory does not exist.
fs.mkdir(dirPath, {recursive:true}, (err)=>{
  if (err) console.log(`Error creating directory: ${err}`)
  // Directory now exists.
})
oldboy
fonte
0

A resposta de Raugaral, mas com a funcionalidade -p. Feio, mas funciona:

function mkdirp(dir) {
    let dirs = dir.split(/\\/).filter(asdf => !asdf.match(/^\s*$/))
    let fullpath = ''

    // Production directory will begin \\, test is on my local drive.
    if (dirs[0].match(/C:/i)) {
        fullpath = dirs[0] + '\\'
    }
    else {
        fullpath = '\\\\' + dirs[0] + '\\'
    }

    // Start from root directory + 1, build out one level at a time.
    dirs.slice(1).map(asdf => {
        fullpath += asdf + '\\'
        if (!fs.existsSync(fullpath)) {
            fs.mkdirSync(fullpath)
        }
    })
}//mkdirp
user8675309
fonte
0

Assim como uma alternativa mais nova à resposta de Teemu Ikonen , que é muito simples e de fácil leitura, é usar o ensureDirmétodo dafs-extra pacote.

Ele não só pode ser usado como um substituto flagrante do fsmódulo embutido , mas também possui muitas outras funcionalidades, além das funcionalidades dofs pacote.

O ensureDirmétodo, como o nome sugere, garante que o diretório exista. Se a estrutura de diretórios não existir, ela será criada. Gostarmkdir -p . Não apenas a pasta final, o caminho inteiro é criado, se já não existir.

o fornecido acima é a sua asyncversão. Ele também possui um método síncrono para executar isso na forma do ensureDirSyncmétodo.

Rai
fonte
0

A resposta do @ Liberateur acima não funcionou para mim (nó v8.10.0). Poucas modificações foram suficientes, mas não tenho certeza se esse é o caminho certo. Por favor sugira.

// Get modules node
const fs   = require('fs');
const path = require('path');

// Create
function mkdirpath(dirPath)
{
    try {
        fs.accessSync(dirPath, fs.constants.R_OK | fs.constants.W_OK);
    }
    catch(err) {
        try
        {
            fs.mkdirSync(dirPath);
        }
        catch(e)
        {
            mkdirpath(path.dirname(dirPath));
            mkdirpath(dirPath);
        }
    }
}

// Create folder path
mkdirpath('my/new/folder/create');
nik
fonte