Come posso verificare in modo sincrono, usando node.js , se esiste un file o una directory?
exists
aggiunge solo richiami non necessari.
Come posso verificare in modo sincrono, usando node.js , se esiste un file o una directory?
exists
aggiunge solo richiami non necessari.
Risposte:
La risposta a questa domanda è cambiata nel corso degli anni. La risposta attuale è qui in alto, seguita dalle varie risposte nel corso degli anni in ordine cronologico:
Puoi usare fs.existsSync()
:
const fs = require("fs"); // Or `import fs from "fs";` with ESM
if (fs.existsSync(path)) {
// Do something
}
È stato deprecato per diversi anni, ma non lo è più. Dai documenti:
Si noti che
fs.exists()
è deprecato, mafs.existsSync()
non lo è. (Il parametro callback perfs.exists()
accettare parametri incoerenti con altri callback Node.js.fs.existsSync()
Non utilizza un callback.)
Hai richiesto specificamente un controllo sincrono , ma se invece puoi utilizzare un controllo asincrono (di solito meglio con I / O), usa fs.promises.access
se stai usando async
funzioni o fs.access
(dato che exists
è deprecato ) in caso contrario:
In una async
funzione:
try {
await fs.promises.access("somefile");
// The check succeeded
} catch (error) {
// The check failed
}
O con un callback:
fs.access("somefile", error => {
if (!error) {
// The check succeeded
} else {
// The check failed
}
});
Ecco le risposte storiche in ordine cronologico:
stat
/ statSync
o lstat
/ lstatSync
)exists
/ existsSync
)exists
/ existsSync
, quindi probabilmente torniamo a stat
/ statSync
o lstat
/ lstatSync
)fs.access(path, fs.F_OK, function(){})
/ fs.accessSync(path, fs.F_OK)
, ma nota che se il file / directory non esiste, è un errore; documenti da fs.stat
utilizzare fs.access
se è necessario verificare l'esistenza senza aprirla)fs.exists()
è ancora obsoleto ma fs.existsSync()
non è più obsoleto. Quindi puoi usarlo tranquillamente ora.Puoi usare statSync
o lstatSync
( link docs ), che ti dà un fs.Stats
oggetto . In generale, se è disponibile una versione sincrona di una funzione, avrà lo stesso nome della versione asincrona con Sync
alla fine. Così statSync
è la versione sincrona di stat
; lstatSync
è la versione sincrona di lstat
, ecc.
lstatSync
ti dice se esiste qualcosa e, in tal caso, se si tratta di un file o di una directory (o in alcuni file system, un collegamento simbolico, un dispositivo a blocchi, un dispositivo a caratteri, ecc.), ad esempio se devi sapere se esiste e lo è una directory:
var fs = require('fs');
try {
// Query the entry
stats = fs.lstatSync('/the/path');
// Is it a directory?
if (stats.isDirectory()) {
// Yes it is
}
}
catch (e) {
// ...
}
... e similmente, se è un file, c'è isFile
; se è un dispositivo a blocchi, c'è isBlockDevice
, ecc. ecc. Nota il try/catch
; genera un errore se la voce non esiste affatto.
Se non vi interessa ciò che la voce è solo vuole sapere se esiste, è possibile utilizzare path.existsSync
(o con l'ultima, fs.existsSync
), come notato da user618408 :
var path = require('path');
if (path.existsSync("/the/path")) { // or fs.existsSync
// ...
}
Non richiede un try/catch
ma non ti dà informazioni su cosa sia, solo che è lì. path.existsSync
è stato deprecato molto tempo fa.
Nota a margine: hai chiesto espressamente come verificare in modo sincrono , quindi ho usato le xyzSync
versioni delle funzioni sopra. Ma dove possibile, con l'I / O, è davvero meglio evitare chiamate sincrone. Le chiamate nel sottosistema I / O richiedono molto tempo dal punto di vista della CPU. Nota quanto è facile chiamare lstat
piuttosto che lstatSync
:
// Is it a directory?
lstat('/the/path', function(err, stats) {
if (!err && stats.isDirectory()) {
// Yes it is
}
});
Ma se hai bisogno della versione sincrona, è lì.
La risposta di seguito di un paio di anni fa è ora un po 'obsoleta. Il modo attuale è quello di usare fs.existsSync
un controllo sincrono per l'esistenza di file / directory (o ovviamente fs.exists
per un controllo asincrono), piuttosto che le path
versioni sottostanti.
Esempio:
var fs = require('fs');
if (fs.existsSync(path)) {
// Do something
}
// Or
fs.exists(path, function(exists) {
if (exists) {
// Do something
}
});
Ed eccoci nel 2015 e i documenti di Node ora dicono che fs.existsSync
(e fs.exists
) "saranno deprecati". (Perché la gente del Nodo pensa che sia stupido controllare se esiste qualcosa prima di aprirlo, ma non è l'unica ragione per verificare se esiste qualcosa!)
Quindi probabilmente torniamo ai vari stat
metodi ... Fino a / a meno che questo non cambi ancora, naturalmente.
Non so da quanto tempo è lì, ma c'è anche fs.access(path, fs.F_OK, ...)
/fs.accessSync(path, fs.F_OK)
. E almeno a partire da ottobre 2016, la fs.stat
documentazione consiglia di utilizzare fs.access
per eseguire controlli di esistenza ( "Per verificare se esiste un file senza manipolarlo in seguito, fs.access()
si consiglia." ). Ma tieni presente che l'accesso non disponibile è considerato un errore , quindi questo sarebbe probabilmente il migliore se ti aspetti che il file sia accessibile:
var fs = require('fs');
try {
fs.accessSync(path, fs.F_OK);
// Do something
} catch (e) {
// It isn't accessible
}
// Or
fs.access(path, fs.F_OK, function(err) {
if (!err) {
// Do something
} else {
// It isn't accessible
}
});
Puoi usare fs.existsSync()
:
if (fs.existsSync(path)) {
// Do something
}
È stato deprecato per diversi anni, ma non lo è più. Dai documenti:
Si noti che
fs.exists()
è deprecato, mafs.existsSync()
non lo è. (Il parametro callback perfs.exists()
accettare parametri incoerenti con altri callback Node.js.fs.existsSync()
Non utilizza un callback.)
open
chiamata e gestire l'eccezione o qualunque altra cosa se il file non lo fosse trovato. Dopotutto, il mondo reale è caotico: se controlli prima ed è lì, ciò non significa che sarà ancora lì quando provi ad aprirlo; se controlli prima e non è lì, ciò non significa che non ci sarà un momento dopo. Le cose del genere sembrano casi limite, ma arrivano sempre . Quindi, se hai intenzione di aprire, non ha senso controllare prima.
Guardando la fonte, c'è una versione sincrona di path.exists
- path.existsSync
. Sembra che ci sia mancato nei documenti.
path.exists
e path.existsSync
ora sono deprecati . Si prega di utilizzare .fs.exists
efs.existsSync
fs.exists
e stati fs.existsSync
sono anche deprecati . Utilizzare invece fs.stat () o fs.access () .
usare fs.existsSync
. Non è deprecato.
https://nodejs.org/api/fs.html#fs_fs_existssync_path
fs.existsSync
.
exists
funzione:is-there
fs.exists
come deprecato mentre fs.existsSync
non lo è!
Utilizzando le API attualmente consigliate (a partire dal 2015) (secondo i documenti Node), questo è quello che faccio:
var fs = require('fs');
function fileExists(filePath)
{
try
{
return fs.statSync(filePath).isFile();
}
catch (err)
{
return false;
}
}
In risposta alla questione EPERM sollevata da @broadband nei commenti, ciò evidenzia un buon punto. fileExists () probabilmente non è un buon modo di pensarci in molti casi, perché fileExists () non può davvero promettere un ritorno booleano. Potresti essere in grado di determinare definitivamente che il file esiste o non esiste, ma potresti anche ricevere un errore di autorizzazione. L'errore di autorizzazione non implica necessariamente che il file esista, perché potresti non avere l'autorizzazione per la directory che contiene il file su cui stai controllando. E ovviamente c'è la possibilità che potresti riscontrare qualche altro errore nel controllo dell'esistenza del file.
Quindi il mio codice sopra è davvero doesFileExistAndDoIHaveAccessToIt (), ma la tua domanda potrebbe essere doFileNotExistAndCouldICreateIt (), che sarebbe una logica completamente diversa (che dovrebbe tenere conto di un errore EPERM, tra le altre cose).
Mentre la risposta fs.existsSync affronta direttamente la domanda posta qui, spesso non sarà quello che vuoi (non vuoi solo sapere se "qualcosa" esiste in un percorso, probabilmente ti importa se la "cosa" che esiste è un file o una directory).
La linea di fondo è che se stai verificando se esiste un file, probabilmente lo stai facendo perché intendi intraprendere alcune azioni in base al risultato e che la logica (il controllo e / o l'azione successiva) dovrebbe adattarsi all'idea che una cosa trovata in quel percorso potrebbe essere un file o una directory e che potresti riscontrare EPERM o altri errori nel processo di verifica.
file.exists()
utilità per il 3% e invece ci costringi a concludere questo in un tentativo di cattura? Diventa reale ... Puttana del giorno.
Un altro aggiornamento
Ho bisogno di una risposta a questa domanda io stesso ho cercato i documenti del nodo, sembra che non dovresti usare fs.exists, invece usa fs.open e usa l'errore emesso per rilevare se un file non esiste:
dai documenti:
fs.exists () è un anacronismo ed esiste solo per ragioni storiche. Non dovrebbe esserci quasi mai un motivo per usarlo nel tuo codice.
In particolare, controllare se esiste un file prima di aprirlo è un anti-pattern che ti rende vulnerabile alle condizioni di gara: un altro processo può rimuovere il file tra le chiamate a fs.exists () e fs.open (). Basta aprire il file e gestire l'errore quando non è presente.
Uso la funzione di seguito per verificare se il file esiste. Cattura anche altre eccezioni. Quindi, nel caso in cui ci siano problemi di diritti, ad esempio chmod ugo-rwx filename
o nella Right Click -> Properties -> Security -> Advanced -> Permission entries: empty list ..
funzione di Windows
, si ottiene l'eccezione come dovrebbe. Il file esiste ma non abbiamo i diritti per accedervi. Sarebbe sbagliato ignorare questo tipo di eccezioni.
function fileExists(path) {
try {
return fs.statSync(path).isFile();
}
catch (e) {
if (e.code == 'ENOENT') { // no such file or directory. File really does not exist
console.log("File does not exist.");
return false;
}
console.log("Exception fs.statSync (" + path + "): " + e);
throw e; // something else went wrong, we don't have rights, ...
}
}
Output delle eccezioni, documentazione degli errori nodejs nel caso in cui il file non esista:
{
[Error: ENOENT: no such file or directory, stat 'X:\\delsdfsdf.txt']
errno: -4058,
code: 'ENOENT',
syscall: 'stat',
path: 'X:\\delsdfsdf.txt'
}
Eccezione nel caso in cui non abbiamo diritti sul file, ma esiste:
{
[Error: EPERM: operation not permitted, stat 'X:\file.txt']
errno: -4048,
code: 'EPERM',
syscall: 'stat',
path: 'X:\\file.txt'
}
fs.exists () è deprecato, non utilizzarlo https://nodejs.org/api/fs.html#fs_fs_exists_path_callback
È possibile implementare il modo nodejs core utilizzato in questo modo: https://github.com/nodejs/node-v0.x-archive/blob/master/lib/module.js#L86
function statPath(path) {
try {
return fs.statSync(path);
} catch (ex) {}
return false;
}
questo restituirà l'oggetto stats quindi una volta ottenuto l'oggetto stats potresti provare
var exist = statPath('/path/to/your/file.js');
if(exist && exist.isFile()) {
// do something
}
Alcune risposte qui lo dicono fs.exists
e fs.existsSync
sono entrambe deprecate. Secondo i documenti questo non è più vero. Solo fs.exists
ora è deprecato:
Nota che fs.exists () è deprecato, ma fs.existsSync () non lo è. (Il parametro callback su fs.exists () accetta parametri incompatibili con altri callback di Node.js. Fs.existsSync () non utilizza un callback.)
Quindi puoi tranquillamente usare fs.existsSync () per verificare in modo sincrono se esiste un file.
Il path
modulo non fornisce una versione sincrona di path.exists
quindi devi cercare con il fs
modulo.
La cosa più veloce che posso immaginare è usare fs.realpathSync
che genererà un errore che devi catturare, quindi devi far funzionare il tuo wrapper con un tentativo / cattura.
L'uso dei test di fileSystem (fs) attiverà oggetti di errore, che sarà quindi necessario racchiudere in un'istruzione try / catch. Risparmia un po 'di sforzo e usa una funzionalità introdotta nel ramo 0.4.x.
var path = require('path');
var dirs = ['one', 'two', 'three'];
dirs.map(function(dir) {
path.exists(dir, function(exists) {
var message = (exists) ? dir + ': is a directory' : dir + ': is not a directory';
console.log(message);
});
});
I documenti su fs.stat()
dicono di usare fs.access()
se non hai intenzione di manipolare il file. Non ha fornito una giustificazione, potrebbe essere più veloce o meno un uso memoriale?
Uso il nodo per l'automazione lineare, quindi ho pensato di condividere la funzione che utilizzo per verificare l'esistenza del file.
var fs = require("fs");
function exists(path){
//Remember file access time will slow your program.
try{
fs.accessSync(path);
} catch (err){
return false;
}
return true;
}
asnwer aggiornato per quelle persone 'correttamente' sottolineando che non risponde direttamente alla domanda, più porta un'opzione alternativa.
fs.existsSync('filePath')
vedi anche i documenti qui .
Restituisce vero se esiste il percorso, falso altrimenti.
In un contesto asincrono, puoi semplicemente scrivere la versione asincrona con il metodo di sincronizzazione usando la await
parola chiave. Puoi semplicemente trasformare il metodo di callback asincrono in una promessa come questa:
function fileExists(path){
return new Promise((resolve, fail) => fs.access(path, fs.constants.F_OK,
(err, result) => err ? fail(err) : resolve(result))
//F_OK checks if file is visible, is default does no need to be specified.
}
async function doSomething() {
var exists = await fileExists('filePath');
if(exists){
console.log('file exists');
}
}
i documenti su access ().
function asyncFileExists(path) { //F_OK checks if file is visible, is default does no need to be specified. return new Promise(function (res, rej) { fs.access( path, fs.constants.F_OK, function (err) { err ? rej(err) : res(true); }, ); }); }
È probabile che, se si desidera sapere se esiste un file, si prevede di richiederlo in caso affermativo.
function getFile(path){
try{
return require(path);
}catch(e){
return false;
}
}
Ecco una semplice soluzione wrapper per questo:
var fs = require('fs')
function getFileRealPath(s){
try {return fs.realpathSync(s);} catch(e){return false;}
}
Uso:
Esempio:
var realPath,pathToCheck='<your_dir_or_file>'
if( (realPath=getFileRealPath(pathToCheck)) === false){
console.log('file/dir not found: '+pathToCheck);
} else {
console.log('file/dir exists: '+realPath);
}
Assicurarsi di utilizzare l'operatore === per verificare se return è uguale a false. Non vi è alcun motivo logico che fs.realpathSync () restituisca false in condizioni di lavoro adeguate, quindi penso che dovrebbe funzionare al 100%.
Preferirei vedere una soluzione che non genera un errore e il conseguente risultato delle prestazioni. Dal punto di vista dell'API, fs.exists () sembra la soluzione più elegante.
Dalle risposte sembra che non ci sia supporto API ufficiale per questo (come in un controllo diretto ed esplicito). Molte delle risposte dicono di usare stat, tuttavia non sono rigide. Non possiamo supporre, ad esempio, che qualsiasi errore generato da stat significhi che qualcosa non esiste.
Diciamo che lo proviamo con qualcosa che non esiste:
$ node -e 'require("fs").stat("god",err=>console.log(err))'
{ Error: ENOENT: no such file or directory, stat 'god' errno: -2, code: 'ENOENT', syscall: 'stat', path: 'god' }
Proviamo con qualcosa che esiste ma che non abbiamo accesso a:
$ mkdir -p fsm/appendage && sudo chmod 0 fsm
$ node -e 'require("fs").stat("fsm/appendage",err=>console.log(err))'
{ Error: EACCES: permission denied, stat 'access/access' errno: -13, code: 'EACCES', syscall: 'stat', path: 'fsm/appendage' }
Almeno vorrai:
let dir_exists = async path => {
let stat;
try {
stat = await (new Promise(
(resolve, reject) => require('fs').stat(path,
(err, result) => err ? reject(err) : resolve(result))
));
}
catch(e) {
if(e.code === 'ENOENT') return false;
throw e;
}
if(!stat.isDirectory())
throw new Error('Not a directory.');
return true;
};
La domanda non è chiara se si desidera che sia sincrona o se si desidera solo che sia scritta come se fosse sincrona. In questo esempio viene usato waitit / async in modo che sia scritto solo in modo sincrono ma venga eseguito in modo asincrono.
Ciò significa che devi chiamarlo come tale al livello superiore:
(async () => {
try {
console.log(await dir_exists('god'));
console.log(await dir_exists('fsm/appendage'));
}
catch(e) {
console.log(e);
}
})();
Un'alternativa sta usando .then e .catch sulla promessa restituita dalla chiamata asincrona se ne hai bisogno più in basso.
Se vuoi verificare se esiste qualcosa, allora è una buona pratica assicurarsi anche che sia il giusto tipo di cose come una directory o un file. Questo è incluso nell'esempio. Se non è consentito essere un collegamento simbolico, è necessario utilizzare lstat anziché stat poiché stat attraverserà automaticamente i collegamenti.
Puoi sostituire tutto l'asincrono per sincronizzare il codice qui e utilizzare invece statSync. Tuttavia, aspettati che una volta che asincrono e attendi diventino universalmente supportati, le chiamate di sincronizzazione diventeranno ridondanti alla fine per essere ammortizzate (altrimenti dovresti definirle ovunque e in cima alla catena proprio come con asincrono che lo rende davvero inutile).