Qual é a diferença entre __dirname e ./ no node.js?


498

Ao programar no Node.js e referenciar arquivos localizados em algum lugar em relação ao seu diretório atual, existe algum motivo para usar a __dirnamevariável em vez de apenas uma regular ./? Eu tenho usado ./ até agora no meu código e descobri a existência de __dirname, e quero essencialmente saber se seria inteligente converter meus ./ para isso e, se sim, por que essa seria uma idéia inteligente .


47
tl; dr: Então, basicamente, a diferença é que './' e 'process.cwd ()' se referem ao diretório atual do terminal que chama o script, enquanto o '__dirname' refere-se ao diretório em que o script é armazenado.
Gui Imamura

1
Exceto quando .é usado dentro require. O caminho interno requireé sempre relativo ao arquivo que contém a chamada para require.
Govind Rai

Respostas:


814

A essência

No Node.js, __dirnameé sempre o diretório em que o script atualmente em execução reside ( veja isso ). Então, se você digitou __dirnameem /d1/d2/myscript.js, o valor seria /d1/d2.

Por outro lado, .fornece o diretório a partir do qual você executou o nodecomando na janela do terminal (ou seja, o diretório de trabalho) quando você usa bibliotecas como pathe fs. Tecnicamente, ele começa como seu diretório de trabalho, mas pode ser alterado usando process.chdir().

A exceção é quando você usa .com require(). O caminho interno requireé sempre relativo ao arquivo que contém a chamada para require.

Por exemplo...

Digamos que sua estrutura de diretórios seja

/dir1
  /dir2
    pathtest.js

e pathtest.jscontém

var path = require("path");
console.log(". = %s", path.resolve("."));
console.log("__dirname = %s", path.resolve(__dirname));

e você faz

cd /dir1/dir2
node pathtest.js

você recebe

. = /dir1/dir2
__dirname = /dir1/dir2

Seu diretório de trabalho é /dir1/dir2o que .resolve. Desde que pathtest.jsestá localizado em /dir1/dir2que é o que __dirnameresolve também.

No entanto, se você executar o script a partir de /dir1

cd /dir1
node dir2/pathtest.js

você recebe

. = /dir1
__dirname = /dir1/dir2

Nesse caso, seu diretório de trabalho era /dir1e foi assim que .resolveu, mas __dirnameainda resolve /dir1/dir2.

Usando .dentro require...

Se dentro de dir2/pathtest.jsvocê tiver uma requirechamada para incluir um arquivo dentro, dir1você sempre faria

require('../thefile')

porque o caminho interno requireé sempre relativo ao arquivo no qual você está chamando. Não tem nada a ver com o seu diretório de trabalho.


38
Na IMO, essa explicação é um pouco mais clara que a da resposta aceita (você sabe, "o diretório atual" é um pouco ambíguo).
encarnou

5
Concordo. Vou mudar a resposta aceita. Lembre-se de que esta resposta foi adicionada 2,5 anos após a original ter sido aceita, e eu só a notei agora (outros 2 anos depois). :) Antes tarde do que nunca!
precisa saber é o seguinte

14
Vale ressaltar que ./nem sempre é o diretório em que o nó foi iniciado. Começa assim, mas pode ser alterado via process.chdir(). Portanto, ./sempre é o diretório de trabalho atual, que geralmente é o nó do diretório, a menos que seu código altere explicitamente o diretório de trabalho.
precisa saber é o seguinte

3
Estou um pouco confuso sobre o uso. inside exigir parte, se o caminho dentro de exigir é sempre relativo ao arquivo que você está chamando, o caminho não deve ser obrigatório ('../arquivo') em vez de exigir ('../dir1 / arquivo')? Eu pensei que o .. trazer a posição atual do caminho de volta um nível de dir2 para dir1 já. Você ainda precisa colocar dir1 no caminho ou sinto falta de algo?
precisa saber é o seguinte

1
E como você faria se precisasse usar ../someDiralgum script e executar o comando em uma pasta diferente?
Cbdeveloper 5/11/19

154

./refere-se ao diretório de trabalho atual, exceto na require()função Ao usá- require()lo, ele se traduz ./no diretório do arquivo atual chamado. __dirnameé sempre o diretório do arquivo atual.

Por exemplo, com a seguinte estrutura de arquivo

/home/user/dir/files/config.json

{
  "hello": "world"
}

/home/user/dir/files/somefile.txt

text file

/home/user/dir/dir.js

var fs = require('fs');

console.log(require('./files/config.json'));
console.log(fs.readFileSync('./files/somefile.txt', 'utf8'));

Se eu cdentrar /home/user/dire correr node dir.js, terei

{ hello: 'world' }
text file

Mas quando executo o mesmo script /home/user/, recebo

{ hello: 'world' }

Error: ENOENT, no such file or directory './files/somefile.txt'
    at Object.openSync (fs.js:228:18)
    at Object.readFileSync (fs.js:119:15)
    at Object.<anonymous> (/home/user/dir/dir.js:4:16)
    at Module._compile (module.js:432:26)
    at Object..js (module.js:450:10)
    at Module.load (module.js:351:31)
    at Function._load (module.js:310:12)
    at Array.0 (module.js:470:10)
    at EventEmitter._tickCallback (node.js:192:40)

Usando ./trabalhou com requiremas não para fs.readFileSync. Isso porque fs.readFileSync, ./traduz-se no cwd (neste caso /home/user/). E /home/user/files/somefile.txtnão existe.


oh, pensei que __dirname fosse o diretório de trabalho atual ... obrigado pelo esclarecimento!
thisissami

Existe alguma maneira de referenciar o diretório de trabalho do aplicativo com fs? Por exemplo, eu estou tentando carregar um arquivo do diretório de trabalho /movies, mas desde que meu módulo está em um arquivo /custom_modules/, __dirnametenta agarrar o filme a partir,/custom_modules/movies

2
Você pode usar ./ou process.cwd(). veja nodejs.org/api/process.html#process_process_cwd
fent

Vale ressaltar que não é uma boa idéia usar __dirname sobre ./ em instruções exigem, porque, embora se comportem de forma idêntica no nó, isso pode causar problemas nas compilações do browserify para pacotes que são facilmente evitados.
Jed Watson
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.