Compruebe sincrónicamente si el archivo / directorio existe en Node.js

1209

¿Cómo puedo verificar sincrónicamente, usando node.js , si existe un archivo o directorio?

Ragnis
fuente
58
Las operaciones sincrónicas son excelentes para realizar operaciones únicas de archivo / directorio antes de devolver un módulo. Por ejemplo, iniciar un archivo de configuración.
jocull
1
@PaulDraper con un caché cálido no es cierto en todos los casos.
mikemaccana
12
No importa las actuaciones, a veces solo quieres ejecutarlo de forma sincronizada para la experiencia del desarrollador. Por ejemplo, si está utilizando Node para un script de procesamiento de datos que, por diseño, debería estar bloqueando, en ese caso, async existssolo agrega devoluciones de llamada innecesarias.
Kunok
3
Definitivamente +1 a la declaración de Kunok. En el resto de mi código, solo hago el código más complejo cuando es un cuello de botella donde la velocidad realmente importa. ¿Por qué no aplicaría ese principio a la lectura de archivos? En muchas partes de muchos programas, la simplicidad / legibilidad del código puede ser más importante que la velocidad de ejecución. Si es un área de cuello de botella, usaré métodos asincrónicos para evitar detener la ejecución de código adicional. De lo contrario ... la sincronización es genial. No odies ciegamente la sincronización.
BryanGrezeszak
3
Por favor ... no "vale la pena señalar" porque el usuario pregunta explícitamente cómo hacerlo de forma sincrónica.
jClark

Respuestas:

2241

La respuesta a esta pregunta ha cambiado con los años. La respuesta actual está aquí en la parte superior, seguida de varias respuestas a lo largo de los años en orden cronológico:

Respuesta actual

Puedes usar fs.existsSync():

const fs = require("fs"); // Or `import fs from "fs";` with ESM
if (fs.existsSync(path)) {
    // Do something
}

Fue en desuso durante varios años, pero ya no lo es. De los documentos:

Tenga en cuenta que fs.exists()está en desuso, pero fs.existsSync()no lo está. (El parámetro de devolución de llamada para fs.exists()aceptar parámetros que son inconsistentes con otras devoluciones de llamada de Node.js. fs.existsSync()No utiliza una devolución de llamada).

Ha solicitado específicamente una verificación sincrónica , pero si puede usar una verificación asincrónica en su lugar (generalmente mejor con E / S), use fs.promises.accesssi está utilizando asyncfunciones o fs.access(dado que existsestá en desuso ) si no:

En una asyncfunción:

try {
    await fs.promises.access("somefile");
    // The check succeeded
} catch (error) {
    // The check failed
}

O con una devolución de llamada:

fs.access("somefile", error => {
    if (!error) {
        // The check succeeded
    } else {
        // The check failed
    }
});

Respuestas Históricas

Aquí están las respuestas históricas en orden cronológico:

  • Respuesta original de 2010
    ( stat/ statSynco lstat/ lstatSync)
  • Actualización de septiembre de 2012
    ( exists/ existsSync)
  • Actualización de febrero de 2015
    (teniendo en cuenta la inminente desaprobación de exists/ existsSync, por lo que probablemente volvamos a stat/ statSynco lstat/ lstatSync)
  • Actualización de diciembre de 2015
    (También hay fs.access(path, fs.F_OK, function(){})/ fs.accessSync(path, fs.F_OK), pero tenga en cuenta que si el archivo / directorio no existe, es un error; documentos para fs.statrecomendar usar fs.accesssi necesita verificar la existencia sin abrir)
  • La actualización de diciembre de 2016
    fs.exists() todavía está en desuso, pero fs.existsSync()ya no está en desuso. Para que pueda usarlo con seguridad ahora.

Respuesta original de 2010:

Puedes usar statSynco lstatSync( docs link ), que te da un fs.Statsobjeto . En general, si una versión síncrona de una función está disponible, tendrá el mismo nombre que la versión asíncrona con Syncal final. Así statSynces la versión sincrónica de stat; lstatSynces la versión sincrónica de lstat, etc.

lstatSync le informa a ambos si algo existe y, de ser así, si se trata de un archivo o un directorio (o en algunos sistemas de archivos, un enlace simbólico, un dispositivo de bloque, un dispositivo de caracteres, etc.), por ejemplo, si necesita saber si existe y si existe un directorio:

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) {
    // ...
}

... y de manera similar, si es un archivo, hay isFile; si es un dispositivo de bloque, hay isBlockDevice, etc., etc. Tenga en cuenta que try/catch; arroja un error si la entrada no existe en absoluto.

Si no le importa lo que la entrada es y sólo quiere saber si es que existe, puede utilizar path.existsSync(o con la última, fs.existsSync) como se ha señalado por user618408 :

var path = require('path');
if (path.existsSync("/the/path")) { // or fs.existsSync
    // ...
}

No requiere un try/catchpero no le da información sobre qué es la cosa, solo que está allí. path.existsSyncfue en desuso hace mucho tiempo.


Nota al margen: Usted ha preguntado expresamente cómo verificar sincrónicamente , por lo que he usado las xyzSyncversiones de las funciones anteriores. Pero siempre que sea posible, con E / S, lo mejor es evitar las llamadas sincrónicas. Las llamadas al subsistema de E / S toman un tiempo considerable desde el punto de vista de una CPU. Tenga en cuenta lo fácil que es llamar en lstatlugar de lstatSync:

// Is it a directory?
lstat('/the/path', function(err, stats) {
    if (!err && stats.isDirectory()) {
        // Yes it is
    }
});

Pero si necesita la versión sincrónica, está ahí.

Actualización de septiembre de 2012

La siguiente respuesta de hace un par de años ahora está un poco desactualizada. La forma actual es usar fs.existsSyncpara hacer una verificación sincrónica de la existencia de un archivo / directorio (o, por supuesto, fs.existspara una verificación asincrónica), en lugar de las pathversiones a continuación.

Ejemplo:

var fs = require('fs');

if (fs.existsSync(path)) {
    // Do something
}

// Or

fs.exists(path, function(exists) {
    if (exists) {
        // Do something
    }
});

Actualización febrero 2015

Y aquí estamos en 2015 y los documentos del Nodo ahora dicen que fs.existsSync(y fs.exists) "quedarán en desuso". (Debido a que la gente del Nodo piensa que es tonto verificar si algo existe antes de abrirlo, lo cual es; ¡pero esa no es la única razón para verificar si algo existe!)

Así que probablemente volvamos a los diversos statmétodos ... Hasta / a menos que esto cambie una vez más, por supuesto.

Actualización de diciembre de 2015

No sé cuánto tiempo lleva allí, pero también hay fs.access(path, fs.F_OK, ...)/fs.accessSync(path, fs.F_OK) . Y al menos a partir de octubre de 2016, la fs.statdocumentación recomienda usar fs.accesspara hacer verificaciones de existencia ( " fs.access()Se recomienda verificar si un archivo existe sin manipularlo después " ). Pero tenga en cuenta que el acceso que no está disponible se considera un error , por lo que probablemente sea mejor si espera que el archivo sea accesible:

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
    }
});

Actualización de diciembre de 2016

Puedes usar fs.existsSync():

if (fs.existsSync(path)) {
    // Do something
}

Fue en desuso durante varios años, pero ya no lo es. De los documentos:

Tenga en cuenta que fs.exists()está en desuso, pero fs.existsSync()no lo está. (El parámetro de devolución de llamada para fs.exists()aceptar parámetros que son inconsistentes con otras devoluciones de llamada de Node.js. fs.existsSync()No utiliza una devolución de llamada).

TJ Crowder
fuente
77
path.exists y path.existsSync han quedado en desuso a favor de fs.exists y fs.existsSync
Drew
15
"La gente de los nodos piensa que es tonto verificar si algo existe antes de abrirlo, que es"; ¿Por qué es tonto verificar si el archivo existe?
Petr Hurtak
32
@PetrHurtak: No siempre es así (porque hay muchas razones para verificar la existencia), pero si va a abrir el archivo, es mejor emitir la openllamada y manejar la excepción o lo que sea si el archivo no fue encontró. Después de todo, el mundo real es caótico: si comprueba primero y está allí, eso no significa que seguirá estando allí cuando intente abrirlo; si verifica primero y no está allí, eso no significa que no estará allí un momento después. Momentos así parecen ser casos extremos, pero surgen todo el tiempo . Entonces, si va a abrir, no tiene sentido verificar primero.
TJ Crowder
13
Y aquí pensé que era un anti-patrón usar errores para el flujo de control: enlace
argyle
44
@jeromeyers: Podrías, pero Ionică ya lo ha hecho por ti (ver comentario más arriba ). :-)
TJ Crowder
124

Mirando la fuente, hay una versión sincrónica de path.exists- path.existsSync. Parece que se perdió en los documentos.

Actualizar:

path.existsy path.existsSyncahora están en desuso . Por favor use fs.existsyfs.existsSync .

Actualización 2016:

fs.exists y fs.existsSynctambién han quedado en desuso . Utilice fs.stat () o fs.access () en su lugar.

Actualización 2019:

uso fs.existsSync. No está en desuso. https://nodejs.org/api/fs.html#fs_fs_existssync_path

Jeff
fuente
1
path.existsSync (p) está en 0.4.10 docs nodejs.org/docs/v0.4.10/api/path.html
Paul Beusterien
21
En realidad, una respuesta más reciente: path.existsSync está en desuso. Ahora se llama fs.existsSync.
Olivier Lalonde
99
Ahora los documentos dicen que fs.exists quedará en desuso. nodejs.org/api/fs.html#fs_fs_existssync_path
Greg Hornby
Escribí una pequeña biblioteca para reemplazar la antigua existsfunción:is-there
Ionică Bizău
66
¡documentos currenct (versión ~ 9) solo etiquetados fs.existscomo obsoletos mientras fs.existsSyncque no lo están!
Kunok
57

Utilizando las API actualmente recomendadas (a partir de 2015) (según los documentos del nodo), esto es lo que hago:

var fs = require('fs');

function fileExists(filePath)
{
    try
    {
        return fs.statSync(filePath).isFile();
    }
    catch (err)
    {
        return false;
    }
}

En respuesta a la cuestión EPERM planteada por @broadband en los comentarios, eso plantea un buen punto. fileExists () probablemente no sea una buena manera de pensar en esto en muchos casos, porque fileExists () realmente no puede prometer un retorno booleano. Es posible que pueda determinar definitivamente que el archivo existe o no, pero también puede obtener un error de permisos. El error de permisos no implica necesariamente que el archivo exista, porque es posible que no tenga permiso para el directorio que contiene el archivo en el que está comprobando. Y, por supuesto, existe la posibilidad de que encuentre algún otro error al verificar la existencia del archivo.

Entonces, mi código anterior es realmente doesFileExistAndDoIHaveAccessToIt (), pero su pregunta podría ser doesFileNotExistAndCouldICreateIt (), que sería una lógica completamente diferente (que necesitaría tener en cuenta un error EPERM, entre otras cosas).

Si bien la respuesta fs.existsSync aborda la pregunta que se hace aquí directamente, eso a menudo no va a ser lo que desea (no solo quiere saber si "algo" existe en un camino, probablemente le importe si la "cosa" que existe es un archivo o un directorio).

La conclusión es que si está verificando si existe un archivo, probablemente lo esté haciendo porque tiene la intención de tomar alguna acción basada en el resultado, y esa lógica (la verificación y / o la acción posterior) debe acomodar la idea que algo encontrado en esa ruta puede ser un archivo o un directorio, y que puede encontrar EPERM u otros errores en el proceso de verificación.

BobDickinson
fuente
44
Bien, agregué || isDirectory () para convertirlo en un verificador de archivos / carpetas. var stats = fs.statSync (filePath); return stats.isFile () || stats.isDirectory ();
bob
44
Si el programa no tiene derechos para acceder al archivo, aún devuelve falso aunque el archivo exista, es decir, elimine todos los rigts del archivo chmod ugo-rwx file.txt o en Windows Right Click ... Mensaje de excepción: Excepción fs.statSync (./ f.txt): Error: EPERM: operación no permitida, stat 'X: \ f.txt'. Entonces este caso no está cubierto por el código superior.
banda ancha
2
Wow, JS se retrasa a veces. Entonces, seguro, el 97% de las veces usará el archivo, pero no tendrá una file.exists()utilidad simple para el 3% y, en su lugar, ¿nos obligará a envolver esto en un intento de captura? Se real ... Perra del día.
Expelledboy
20

Otra actualización

Al necesitar una respuesta para esta pregunta, busqué los documentos del nodo, parece que no debería usar fs.exists, en su lugar use fs.open y use el error de salida para detectar si un archivo no existe:

de los documentos:

fs.exists () es un anacronismo y existe solo por razones históricas. Casi nunca debería haber una razón para usarlo en su propio código.

En particular, verificar si existe un archivo antes de abrirlo es un antipatrón que lo deja vulnerable a las condiciones de carrera: otro proceso puede eliminar el archivo entre las llamadas a fs.exists () y fs.open (). Simplemente abra el archivo y maneje el error cuando no esté allí.

http://nodejs.org/api/fs.html#fs_fs_exists_path_callback

Melbourne2991
fuente
1
¿hay alguna manera de hacerlo con openSync, en lugar de abrirlo
Greg Hornby
1
@GregHornby Me imagino que debería funcionar de la misma manera con openSync
Melbourne2991
2
Para los que aún necesito exists y existsSynccreé is-there.
Ionică Bizău
66
Esta deprecación me molesta. Abrir un archivo solo para ver si se produce un error o no parece una pérdida de recursos cuando todo lo que se necesita es conocer la existencia del archivo.
Josh Hansen
11

Yo uso la siguiente función para probar si existe el archivo. Captura también otras excepciones. Entonces, en caso de que haya problemas de derechos, por ejemplo, chmod ugo-rwx filenameo en la Right Click -> Properties -> Security -> Advanced -> Permission entries: empty list ..función de Windows , se devuelve la excepción como debería. El archivo existe pero no tenemos derechos para acceder a él. Sería un error ignorar este tipo de excepciones.

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, ...
  }
}

Salida de excepción, documentación de errores de nodejs en caso de que el archivo no exista:

{
  [Error: ENOENT: no such file or directory, stat 'X:\\delsdfsdf.txt']
  errno: -4058,
  code: 'ENOENT',
  syscall: 'stat',
  path: 'X:\\delsdfsdf.txt'
}

Excepción en caso de que no tengamos derechos sobre el archivo, pero exista:

{
  [Error: EPERM: operation not permitted, stat 'X:\file.txt']
  errno: -4048,
  code: 'EPERM',
  syscall: 'stat',
  path: 'X:\\file.txt'
}
banda ancha
fuente
2
Realmente así, es una de las pocas respuestas actualizadas ya que el nodo ha desaprobado las últimas 37 formas de hacerlo
1mike12
Bah, me ganaste. Podría haber ahorrado algo de tiempo si hubiera leído esto.
jgmjgm
5

fs.exists () está en desuso No lo use https://nodejs.org/api/fs.html#fs_fs_exists_path_callback

Puede implementar el modo core nodejs utilizado en esto: 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;
}

esto devolverá el objeto de estadísticas y, una vez que tenga el objeto de estadísticas, puede intentar

var exist = statPath('/path/to/your/file.js');
if(exist && exist.isFile()) {
  // do something
}
gsalgadotoledo
fuente
4

Algunas respuestas aquí dicen eso fs.existsy fs.existsSyncambos están en desuso. Según los documentos, esto ya no es cierto. Solo fs.existsestá en desuso ahora:

Tenga en cuenta que fs.exists () está en desuso, pero fs.existsSync () no. (El parámetro de devolución de llamada a fs.exists () acepta parámetros que son inconsistentes con otras devoluciones de llamada de Node.js. Fs.existsSync () no utiliza una devolución de llamada).

Por lo tanto, puede usar fs.existsSync () de forma segura para verificar sincrónicamente si existe un archivo.

jstice4all
fuente
3

El pathmódulo no proporciona una versión síncrona, por path.existslo que debe engañar con el fsmódulo.

Lo más rápido que puedo imaginar es usarlo, fs.realpathSynclo que arrojará un error que debe detectar, por lo que debe hacer que su propia función de contenedor con un try / catch.

Ivo Wetzel
fuente
1

El uso de las pruebas de fileSystem (fs) activará objetos de error, que luego deberá incluir en una declaración try / catch. Ahórrese un poco de esfuerzo y use una función introducida en la rama 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);
  });
});

fuente
2
The path.exists ahora está bajo fs, por lo que es fs.exists (ruta, devolución de llamada)
Todd Moses
0

Los documentos sobre fs.stat()dice usar fs.access()si no vas a manipular el archivo. No dio una justificación, ¿podría ser un uso más rápido o menos memorable?

Yo uso el nodo para la automatización lineal, así que pensé en compartir la función que uso para probar la existencia del archivo.

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;
}
Grallen
fuente
0

Respuestas actualizadas para aquellas personas que "correctamente" señalan que no responde directamente a la pregunta, más aportan una opción alternativa.

Solución de sincronización:

fs.existsSync('filePath')También vea los documentos aquí .

Devuelve verdadero si la ruta existe, falso de lo contrario.

Solución de promesa asíncrona

En un contexto asíncrono, podría escribir la versión asíncrona en el método de sincronización con el uso de la awaitpalabra clave. Simplemente puede convertir el método de devolución de llamada asíncrono en una promesa como esta:

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');
  }
}

los documentos sobre acceso ().

Joel Harkes
fuente
1
el OP quiere una solución sincrónica
vdegenne 05 de
debe actualizar su código afunction 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); }, ); }); }
pery mimon
0

Lo más probable es que, si desea saber si existe un archivo, planea solicitarlo si es así.

function getFile(path){
    try{
        return require(path);
    }catch(e){
        return false;
    }
}
SwiftNinjaPro
fuente
-1

Aquí hay una solución de envoltura simple para esto:

var fs = require('fs')
function getFileRealPath(s){
    try {return fs.realpathSync(s);} catch(e){return false;}
}

Uso:

  • Funciona tanto para directorios como para archivos.
  • Si el elemento existe, devuelve la ruta al archivo o directorio
  • Si el elemento no existe, devuelve falso

Ejemplo:

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);
}

Asegúrese de usar el operador === para probar si return es igual a falso. No hay una razón lógica para que fs.realpathSync () devuelva falso en condiciones de trabajo adecuadas, por lo que creo que esto debería funcionar al 100%.

Preferiría ver una solución que no genere un Error y el impacto en el rendimiento resultante. Desde una perspectiva API, fs.exists () parece la solución más elegante.

Timothy C. Quinn
fuente
1
@ Dan, gracias. Eliminé el texto truncado. No puedo recordar cuál era la nota. Si viene, agregaré notas.
Timothy C. Quinn
1
Notario público. Estoy borrando mi comentario.
Dan Dascalescu
-2

De las respuestas parece que no hay soporte oficial de API para esto (como en una verificación directa y explícita). Muchas de las respuestas dicen que use stat, sin embargo, no son estrictas. No podemos suponer, por ejemplo, que cualquier error arrojado por stat significa que algo no existe.

Digamos que lo intentamos con algo que no existe:

$ 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' }

Probémoslo con algo que existe pero al que no tenemos acceso:

$ 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' }

Por lo menos querrás:

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 pregunta no está clara sobre si realmente desea que sea sincrónico o si solo desea que se escriba como si fuera sincrónico. Este ejemplo usa wait / async para que solo se escriba sincrónicamente pero se ejecute de forma asíncrona.

Esto significa que debe llamarlo como tal en el nivel superior:

(async () => {
    try {
        console.log(await dir_exists('god'));
        console.log(await dir_exists('fsm/appendage'));
    }
    catch(e) {
        console.log(e);
    }
})();

Una alternativa es usar .then y .catch en la promesa devuelta por la llamada asincrónica si la necesita más abajo.

Si desea verificar si algo existe, es una buena práctica asegurarse también de que es el tipo correcto de cosas, como un directorio o archivo. Esto está incluido en el ejemplo. Si no se permite que sea un enlace simbólico, debe usar lstat en lugar de stat, ya que stat atravesará automáticamente los enlaces.

Puede reemplazar todo el asíncrono para sincronizar el código aquí y usar statSync en su lugar. Sin embargo, espere que una vez que async y espere se vuelvan universalmente compatibles, las llamadas de Sync se volverán redundantes y eventualmente se depreciarán (de lo contrario, tendría que definirlas en todas partes y en la cadena al igual que con async, lo que lo hace realmente inútil).

jgmjgm
fuente
1
La pregunta original no especifica eso. También estoy demostrando cómo hacer las cosas sin ambigüedades. Muchas respuestas pueden inducir errores debido a la falta de claridad. Las personas a menudo quieren programar cosas para que parezca sincrónico, pero no necesariamente quieren una ejecución sincrónica. statSync no es lo mismo que el código que he demostrado. Cualquiera de las versiones de lo que realmente se desea es ambiguo, por lo que solo está imponiendo sus interpretaciones personales. Si encuentra una respuesta que no comprende, podría ser mejor simplemente preguntar en los comentarios o PM para determinar qué ediciones son necesarias.
jgmjgm
1
Si lo desea, también puede robar mi muestra de código, asígnele un nombre apropiado, póngalo en github, agréguelo a npm y luego la respuesta solo será una línea / enlace: D.
jgmjgm
El código es corto, por ejemplo, pero puede enviar una sugerencia de edición para incluir &&! IsFile o una verificación de enlaces simbólicos, etc. Como ya he señalado, mi respuesta satisface una interpretación de la pregunta y no hace lo mismo que su propuesta de una línea.
jgmjgm