Qual è la differenza tra __dirname e ./ in node.js?


498

Quando si programma in Node.js e si fa riferimento a file che si trovano da qualche parte in relazione alla directory corrente, c'è qualche motivo per usare la __dirnamevariabile invece di un normale ./? Ho usato ./ finora nel mio codice e ho appena scoperto l'esistenza di __dirname, e essenzialmente voglio sapere se sarebbe intelligente convertire i miei ./ in quello, e se sì, perché sarebbe un'idea intelligente .


47
tl; dr: Quindi, sostanzialmente, la differenza è che './' e 'process.cwd ()' si riferiscono alla dir corrente del terminale che chiama lo script, mentre '__dirname' si riferisce alla dir in cui si trova lo script immagazzinato.
Gui Imamura,

1
Tranne quando .viene utilizzato all'interno require. Il percorso all'interno requireè sempre relativo al file contenente la chiamata a require.
Govind Rai

Risposte:


814

L'essenza

In Node.js __dirnameè sempre la directory in cui risiede lo script attualmente in esecuzione ( vedere questo ). Quindi, se avete digitato __dirnamein /d1/d2/myscript.js, il valore sarebbe /d1/d2.

Al contrario, .ti dà la directory da cui hai eseguito il nodecomando nella finestra del tuo terminale (cioè la tua directory di lavoro) quando usi librerie come pathe fs. Tecnicamente, inizia come directory di lavoro ma può essere modificata utilizzando process.chdir().

L'eccezione è quando si usa .con require(). Il percorso all'interno requireè sempre relativo al file contenente la chiamata a require.

Per esempio...

Supponiamo che sia la tua struttura di directory

/dir1
  /dir2
    pathtest.js

e pathtest.jscontiene

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

e tu fai

cd /dir1/dir2
node pathtest.js

hai capito

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

La tua directory di lavoro è /dir1/dir2quindi questo è ciò che si .risolve. Dato che pathtest.jssi trova in /dir1/dir2questo è ciò che si __dirnamerisolve anche.

Tuttavia, se si esegue lo script da /dir1

cd /dir1
node dir2/pathtest.js

hai capito

. = /dir1
__dirname = /dir1/dir2

In quel caso, la tua directory di lavoro era /dir1quindi ciò che è stato .risolto, ma __dirnamesi risolve ancora /dir1/dir2.

Usando .dentro require...

Se all'interno dir2/pathtest.jssi dispone di una requirechiamata in includere un file all'interno dir1si dovrebbe sempre fare

require('../thefile')

perché il percorso all'interno requireè sempre relativo al file in cui lo stai chiamando. Non ha nulla a che fare con la tua directory di lavoro.


38
IMO, questa spiegazione è un po 'più chiara di quella della risposta accettata (sai, "la directory corrente" è un po' ambigua lì).
incarnato il

5
Sono d'accordo. Cambierò la risposta accettata. Tieni presente che questa risposta è stata aggiunta 2,5 anni dopo l'accettazione di quella originale e l'ho notata solo ora (altri 2 anni dopo). :) Meglio tardi che mai!
thisissami,

14
Vale la pena notare che ./non è sempre la directory da cui è stato avviato il nodo. Inizia in questo modo, ma può essere modificato tramite process.chdir(). Quindi, ./è sempre la directory di lavoro corrente, che di solito è il nodo da cui è stata avviata, a meno che il codice non abbia cambiato esplicitamente la directory di lavoro.
gilly3,

3
Sono un po 'confuso sull'uso. parte richiedi parte, se il percorso all'interno richiesto è sempre relativo al file che stai chiamando, non è il percorso che dovrebbe essere richiesto ('../ thefile') invece di require ('../ dir1 / thefile')? ho pensato che .. riporta la posizione corrente del percorso indietro di un livello da dir2 a dir1. Hai ancora bisogno di mettere dir1 nel percorso o mi manca capito qualcosa?
Andromada,

1
E come faresti se hai bisogno di usare ../someDiralcuni script e eseguirai il comando da una cartella diversa?
cbdeveloper,

154

./si riferisce alla directory di lavoro corrente, tranne nella require()funzione. Durante l'utilizzo require(), si traduce ./nella directory del file corrente chiamato. __dirnameè sempre la directory del file corrente.

Ad esempio, con la seguente struttura di file

/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 cdentro /home/user/dire corro node dir.jsotterrò

{ hello: 'world' }
text file

Ma quando eseguo la stessa sceneggiatura /home/user/ottengo

{ 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)

Utilizzo ./funzionante requirema non per fs.readFileSync. Questo perché per fs.readFileSync, si ./traduce in CWD (in questo caso /home/user/). E /home/user/files/somefile.txtnon esiste


oh ho pensato che __dirname fosse l'attuale directory di lavoro ... grazie per il chiarimento!
thisissami,

Esiste un modo per fare riferimento alla directory di lavoro dell'app con fs? Ad esempio, sto cercando di caricare un file dalla directory di lavoro /movies, ma dal momento che il mio modulo è in un file /custom_modules/, __dirnamecerca di catturare il filmato da,/custom_modules/movies

2
Puoi usare ./o process.cwd(). vedi nodejs.org/api/process.html#process_process_cwd
fent

Vale la pena notare che non è una buona idea usare __dirname su ./ nelle istruzioni request perché sebbene si comportino in modo identico nel nodo, può causare problemi con build browserify per pacchetti che altrimenti potrebbero essere facilmente evitati.
Jed Watson,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.