Node.js проверяет, существует ли файл

Как проверить наличие файла?

В документации к модулю fs есть описание метода fs.exists(path, callback). Но, как я понимаю, он проверяет наличие только каталогов. И мне нужно проверить файл!

Как это может быть сделано?


person RomanGorbatko    schedule 17.07.2013    source источник
comment
С 2018 года используйте fs.access('file', err => err ? 'does not exist' : 'exists'), см. fs.access.   -  person mb21    schedule 12.01.2019


Ответы (17)


Почему бы просто не попробовать открыть файл? fs.open('YourFile', 'a', function (err, fd) { ... }) в любом случае после минутного поиска попробуйте это:

var path = require('path'); 

path.exists('foo.txt', function(exists) { 
  if (exists) { 
    // do something 
  } 
}); 

// or 

if (path.existsSync('foo.txt')) { 
  // do something 
} 

Для Node.js v0.12.x и выше

Оба path.exists и fs.exists устарели

*Редактировать:

Изменено: else if(err.code == 'ENOENT')

to: else if(err.code === 'ENOENT')

Линтер жалуется на то, что двойное равенство не является тройным.

Использование fs.stat:

fs.stat('foo.txt', function(err, stat) {
    if(err == null) {
        console.log('File exists');
    } else if(err.code === 'ENOENT') {
        // file does not exist
        fs.writeFile('log.txt', 'Some log\n');
    } else {
        console.log('Some other error: ', err.code);
    }
});
person dardar.moh    schedule 17.07.2013
comment
Но, как оказалось, fs.exists тоже работает. У меня были проблемы с правами доступа к файлу. - person RomanGorbatko; 17.07.2013
comment
path.exists на самом деле устарел в пользу fs.exists - person Arnaud Rinquin; 26.05.2014
comment
Любой, кто читает это сейчас (Node.js v0.12.x), имейте в виду, что fs.exists и fs.existsSync также устарели. Лучший способ проверить наличие файла — fs.stat, как показано выше. - person Antrikshy; 29.03.2015
comment
Из документации Node js кажется, что лучший способ, если вы планируете открыть файл после проверки его существования, - это фактически открыть его и обработать ошибки, если он не существует. Поскольку ваш файл может быть удален между проверкой существования и функцией открытия... - person newprog; 13.04.2015
comment
@Antrikshy fs.existsSync больше не устаревает, хотя fs.exists все еще есть. - person RyanZim; 12.10.2017
comment
Это обещание или что? Кажется, не выполняется асинхронно. - person Philll_t; 03.10.2018
comment
Как сказал @newprog, документация Nodejs для fsPromises(fsp) действительно говорит, что они верны: вызов fsp.access(), а затем вызов fsp.open() может ввести состояние гонки, в котором другие процессы могут изменить состояние файла между двумя звонки. Вместо этого [...] откройте/прочитайте/запишите файл напрямую и обработайте ошибку [если] недоступен Последняя часть связанного раздела в документах - person vipatron; 27.11.2019
comment
@Antrikshy nodejs fs documentation только говорит, что fs.exists устарел, но что fs.existsSync в порядке ??? - person oldboy; 03.01.2020
comment
Почему бы просто не попробовать открыть файл? Потому что для этого требуется отловить ошибку и отличить ошибку, возникшую в результате отсутствия файла, от любой другой возможной ошибки, в то время как exists() тип API отвечает на вопрос напрямую и может использоваться непосредственно в условии. - person Szczepan Hołyszewski; 04.01.2021

Изменить: Поскольку узел v10.0.0мы можем использовать fs.promises.access(...)

Пример асинхронного кода, который проверяет, существует ли файл:

function checkFileExists(file) {
  return fs.promises.access(file, fs.constants.F_OK)
           .then(() => true)
           .catch(() => false)
}

Альтернативой статистике может быть использование нового fs.access(...):

минимизированная функция короткого обещания для проверки:

s => new Promise(r=>fs.access(s, fs.constants.F_OK, e => r(!e)))

Пример использования:

let checkFileExists = s => new Promise(r=>fs.access(s, fs.constants.F_OK, e => r(!e)))
checkFileExists("Some File Location")
  .then(bool => console.log(´file exists: ${bool}´))

расширенный способ обещания:

// returns a promise which resolves true if file exists:
function checkFileExists(filepath){
  return new Promise((resolve, reject) => {
    fs.access(filepath, fs.constants.F_OK, error => {
      resolve(!error);
    });
  });
}

или если вы хотите сделать это синхронно:

function checkFileExistsSync(filepath){
  let flag = true;
  try{
    fs.accessSync(filepath, fs.constants.F_OK);
  }catch(e){
    flag = false;
  }
  return flag;
}
person mido    schedule 26.01.2016
comment
Проголосовал за это, безусловно, самый современный (2018 г.) способ определить, существует ли файл в Node.js. - person AKMorris; 16.02.2018
comment
Да, это официально рекомендуемый метод, позволяющий просто проверить, существует ли файл, и последующая манипуляция не ожидается. В противном случае используйте open/write/read и обработайте ошибку. nodejs.org/api/fs.html#fs_fs_stat_path_callback - person Justin; 16.04.2018
comment
В документации я нахожу fs.constants.F_OK и т. д. Можно ли также получить к ним доступ как fs.F_OK? Странный. К тому же лаконичный, что приятно. - person samson; 20.04.2018
comment
Можно попробовать сделать это с помощью fs.promises.access(path, fs.constants.F_OK);, чтобы просто сделать обещание вместо создания обещания. - person Jeremy Trpka; 20.06.2020
comment
Я использовал еще более короткую версию: не существует: !(await fs.stat(path).catch(() => false)) существует: !!(await fs.stat(path).catch(() => false)) - person antitoxic; 26.08.2020
comment
спасибо! первый пример - такой элегантный способ. - person Systems Rebooter; 22.04.2021
comment
Этот код такой уродливый по сравнению с простым fs.exists... действительно интересно, почему они заставляют нас использовать такие альтернативы :'-( - person GLAND_PROPRE; 20.06.2021

Более простой способ сделать это синхронно.

if (fs.existsSync('/etc/file')) {
    console.log('Found file');
}

В документе API описано, как работает existsSync:
Проверьте, существует ли указанный путь, сверившись с файловой системой.

person Paul Ho    schedule 08.10.2014
comment
@Imeurs, но nodejs.org/api/fs.html#fs_fs_existssync_path говорит: обратите внимание, что fs.exists() устарела, а fs.existsSync() — нет. - person HaveF; 09.12.2016
comment
fs.existsSync устарел, но больше не является. - person RyanZim; 12.10.2017
comment
Синхронный проще, но и категорически хуже, потому что вы блокируете весь процесс в ожидании ввода-вывода, а другие задачи не могут выполняться. Примите обещания и асинхронность, которые приложение, вероятно, должно использовать в любом случае, если оно нетривиальное. - person ggorlen; 22.07.2021

Современный способ async/await (Node 12.8.x)

const fileExists = async path => !!(await fs.promises.stat(path).catch(e => false));

const main = async () => {
    console.log(await fileExists('/path/myfile.txt'));
}

main();

Нам нужно использовать fs.stat() or fs.access(), потому что fs.exists(path, callback) теперь устарело

Еще один хороший способ — fs-extra.

person Дмитрий Васильев    schedule 29.08.2019
comment
На пару символов короче и, возможно, легче читать: const fileExists = path => fs.promises.stat(path).then(() => true, () => false); - person ggorlen; 22.07.2021

fs.exists(path, callback) и fs.existsSync(path) теперь устарели, см. https://nodejs.org/api/fs.html#fs_fs_exists_path_callback и https://nodejs.org/api/fs.html#fs_fs_existssync_path.

Чтобы синхронно проверить существование файла, можно использовать ie. fs.statSync(path). Если файл существует, будет возвращен объект fs.Stats, см. https://nodejs.org/api/fs.html#fs_class_fs_stats, в противном случае будет выдана ошибка, которая будет перехвачена оператором try/catch.

var fs = require('fs'),
  path = '/path/to/my/file',
  stats;

try {
  stats = fs.statSync(path);
  console.log("File exists.");
}
catch (e) {
  console.log("File does not exist.");
}
person lmeurs    schedule 20.09.2015
comment
Ссылка, которую вы предоставили для fs.existsync, четко показывает, что она НЕ устарела. Обратите внимание, что fs.exists() устарела, а fs.existsSync() - нет. (Параметр обратного вызова для fs.exists() принимает параметры, несовместимые с другими обратными вызовами Node.js. fs.existsSync() не использует обратный вызов.) - person shreddish; 08.05.2017
comment
первый (сверху) ответ, в котором упоминалось, откуда берется переменная fs - person Dmitry Koroliov; 21.06.2017
comment
На момент написания этого ответа информация была правильной; однако fs.existsSync() больше не считается устаревшим. - person RyanZim; 12.10.2017

Старая версия до V6: здесь документация

  const fs = require('fs');    
  fs.exists('/etc/passwd', (exists) => {
     console.log(exists ? 'it\'s there' : 'no passwd!');
  });
// or Sync

  if (fs.existsSync('/etc/passwd')) {
    console.log('it\'s there');
  }

ОБНОВЛЕНИЕ

Новые версии V6: документация для fs.stat

fs.stat('/etc/passwd', function(err, stat) {
    if(err == null) {
        //Exist
    } else if(err.code == 'ENOENT') {
        // NO exist
    } 
});
person Ignacio Hernández    schedule 22.08.2016
comment
И fs.exists, и fs.existsSync устарели в соответствии со ссылкой, которой вы поделились. - person Andy; 12.09.2016
comment
existsSync не считается устаревшим в соответствии с этим документом, возможно, так было, когда вы его читали. - person Darpan; 12.04.2018

@Fox: отличный ответ! Вот небольшое расширение с некоторыми дополнительными опциями. Это то, что я использовал в последнее время в качестве решения:

var fs = require('fs');

fs.lstat( targetPath, function (err, inodeStatus) {
  if (err) {

    // file does not exist-
    if (err.code === 'ENOENT' ) {
      console.log('No file or directory at',targetPath);
      return;
    }

    // miscellaneous error (e.g. permissions)
    console.error(err);
    return;
  }


  // Check if this is a file or directory
  var isDirectory = inodeStatus.isDirectory();


  // Get file size
  //
  // NOTE: this won't work recursively for directories-- see:
  // http://stackoverflow.com/a/7550430/486547
  //
  var sizeInBytes = inodeStatus.size;

  console.log(
    (isDirectory ? 'Folder' : 'File'),
    'at',targetPath,
    'is',sizeInBytes,'bytes.'
  );


}

P.S. проверьте fs-extra, если вы еще не используете его - это довольно мило. https://github.com/jprichardson/node-fs-extra)

person mikermcneil    schedule 06.12.2013

fs.exists устарел с версии 1.0.0. Вместо этого вы можете использовать fs.stat.

var fs = require('fs');
fs.stat(path, (err, stats) => {
if ( !stats.isFile(filename) ) { // do this 
}  
else { // do this 
}});

Вот ссылка на документацию fs.stats

person Koushik Das    schedule 12.02.2016
comment
stats.isFile() не нужен filename. - person Wtower; 27.09.2016

Есть много неточных комментариев о том, что fs.existsSync() устарело; Нет.

https://nodejs.org/api/fs.html#fs_fs_existssync_path

Обратите внимание, что fs.exists() устарела, а fs.existsSync() — нет.

person chrisw    schedule 18.01.2017

async/await версия с использованием util.promisify с узла 8:

const fs = require('fs');
const { promisify } = require('util');
const stat = promisify(fs.stat);

describe('async stat', () => {
  it('should not throw if file does exist', async () => {
    try {
      const stats = await stat(path.join('path', 'to', 'existingfile.txt'));
      assert.notEqual(stats, null);
    } catch (err) {
      // shouldn't happen
    }
  });
});

describe('async stat', () => {
  it('should throw if file does not exist', async () => {
    try {
      const stats = await stat(path.join('path', 'to', 'not', 'existingfile.txt'));
    } catch (err) {
      assert.notEqual(err, null);
    }
  });
});
person Alexander Zeitler    schedule 02.06.2017

После небольшого эксперимента я обнаружил, что следующий пример с использованием fs.stat является хорошим способом асинхронной проверки существования файла. Он также проверяет, что ваш «файл» является «действительно файлом» (а не каталогом).

Этот метод использует обещания, предполагая, что вы работаете с асинхронной кодовой базой:

const fileExists = path => {
  return new Promise((resolve, reject) => {
    try {
      fs.stat(path, (error, file) => {
        if (!error && file.isFile()) {
          return resolve(true);
        }

        if (error && error.code === 'ENOENT') {
          return resolve(false);
        }
      });
    } catch (err) {
      reject(err);
    }
  });
};

Если файл не существует, промис все равно разрешается, хотя и false. Если файл существует и является каталогом, то он разрешает true. Любые ошибки при попытке прочитать файл будут reject обещать саму ошибку.

person f1lt3r    schedule 28.10.2016

Ну, я сделал это так, как показано на https://nodejs.org/api/fs.html#fs_fs_access_path_mode_callback

fs.access('./settings', fs.constants.F_OK | fs.constants.R_OK | fs.constants.W_OK, function(err){
  console.log(err ? 'no access or dir doesnt exist' : 'R/W ok');

  if(err && err.code === 'ENOENT'){
    fs.mkdir('settings');
  }
});

Есть ли какие-либо проблемы с этим?

person nthapa    schedule 16.07.2016

в старые времена, прежде чем сесть, я всегда проверяю, есть ли стул, а потом сажусь, иначе у меня есть альтернативный план, например, сесть в карету. Теперь сайт node.js предлагает просто пойти (не нужно проверять), и ответ выглядит так:

    fs.readFile( '/foo.txt', function( err, data )
    {
      if(err) 
      {
        if( err.code === 'ENOENT' )
        {
            console.log( 'File Doesn\'t Exist' );
            return;
        }
        if( err.code === 'EACCES' )
        {
            console.log( 'No Permission' );
            return;
        }       
        console.log( 'Unknown Error' );
        return;
      }
      console.log( data );
    } );

код взят с http://fredkschott.com/post/2014/03/understanding-error-first-callbacks-in-node-js/ от марта 2014 года и немного изменен для соответствия требованиям компьютера. Он также проверяет наличие разрешения — удалите разрешение для проверки chmod a-r foo.txt

person user2167003    schedule 21.03.2015

ванильный обратный вызов Nodejs

function fileExists(path, cb){
  return fs.access(path, fs.constants.F_OK,(er, result)=> cb(!err && result)) //F_OK checks if file is visible, is default does no need to be specified.
}

документы говорят, что вы должны использовать access() в качестве замены устаревшему exists()

Nodejs со встроенным обещанием (узел 7+)

function fileExists(path, cb){
  return new Promise((accept,deny) => 
    fs.access(path, fs.constants.F_OK,(er, result)=> cb(!err && result))
  );
}

Популярный JavaScript-фреймворк

fs-extra

var fs = require('fs-extra')
await fs.pathExists(filepath)

Как видите намного проще. И преимущество перед promisify в том, что с этим пакетом у вас есть полный набор текста (полный intellisense/typescript)! В большинстве случаев вы уже включили эту библиотеку, потому что от нее зависят (+-10 000) других библиотек.

person Joel Harkes    schedule 23.12.2016

Вы можете использовать fs.stat, чтобы проверить, является ли цель файлом или каталогом, и вы можете использовать fs.access, чтобы проверить, можете ли вы писать/читать/выполнять файл. (не забудьте использовать path.resolve, чтобы получить полный путь к цели)

Документация:

Полный пример (TypeScript)

import * as fs from 'fs';
import * as path from 'path';

const targetPath = path.resolve(process.argv[2]);

function statExists(checkPath): Promise<fs.Stats> {
  return new Promise((resolve) => {
    fs.stat(checkPath, (err, result) => {
      if (err) {
        return resolve(undefined);
      }

      return resolve(result);
    });
  });
}

function checkAccess(checkPath: string, mode: number = fs.constants.F_OK): Promise<boolean> {
  return new Promise((resolve) => {
    fs.access(checkPath, mode, (err) => {
      resolve(!err);
    });
  });
}

(async function () {
  const result = await statExists(targetPath);
  const accessResult = await checkAccess(targetPath, fs.constants.F_OK);
  const readResult = await checkAccess(targetPath, fs.constants.R_OK);
  const writeResult = await checkAccess(targetPath, fs.constants.W_OK);
  const executeResult = await checkAccess(targetPath, fs.constants.X_OK);
  const allAccessResult = await checkAccess(targetPath, fs.constants.F_OK | fs.constants.R_OK | fs.constants.W_OK | fs.constants.X_OK);

  if (result) {
    console.group('stat');
    console.log('isFile: ', result.isFile());
    console.log('isDir: ', result.isDirectory());
    console.groupEnd();
  }
  else {
    console.log('file/dir does not exist');
  }

  console.group('access');
  console.log('access:', accessResult);
  console.log('read access:', readResult);
  console.log('write access:', writeResult);
  console.log('execute access:', executeResult);
  console.log('all (combined) access:', allAccessResult);
  console.groupEnd();

  process.exit(0);
}());
person BrunoLM    schedule 11.02.2018

Для асинхронной версии! И с обещанной версией! Вот чистый простой способ!

try {
    await fsPromise.stat(filePath);
    /**
     * File exists!
     */
    // do something
} catch (err) {
    if (err.code = 'ENOENT') {
        /**
        * File not found
        */
    } else {
        // Another error!
    }
}

Более практичный фрагмент моего кода для лучшей иллюстрации:


try {
    const filePath = path.join(FILES_DIR, fileName);
    await fsPromise.stat(filePath);
    /**
     * File exists!
     */
    const readStream = fs.createReadStream(
        filePath,
        {
            autoClose: true,
            start: 0
        }
    );

    return {
        success: true,
        readStream
    };
} catch (err) {
    /**
     * Mapped file doesn't exists
     */
    if (err.code = 'ENOENT') {
        return {
            err: {
                msg: 'Mapped file doesn\'t exists',
                code: EErrorCode.MappedFileNotFound
            }
        };
    } else {
        return {
            err: {
                msg: 'Mapped file failed to load! File system error',
                code: EErrorCode.MappedFileFileSystemError
            }
        }; 
   }
}

Пример выше только для демонстрации! Я мог бы использовать событие ошибки потока чтения! Чтобы поймать любые ошибки! И пропустите два звонка!

person Mohamed Allal    schedule 27.05.2020

Использование машинописного текста и fs/promises в node14

import * as fsp from 'fs/promises';
try{
const = await fsp.readFile(fullFileName)
...
} catch(e) { ...}

Лучше использовать fsp.readFile, чем fsp.statили fsp.access по двум причинам:

  1. Наименее важная причина - это одним доступом меньше.
  2. Возможно, что fsp.statи fsp.readFile дадут разные ответы. Либо из-за тонких различий в вопросах, которые они задают, либо из-за того, что статус файлов изменился между звонками. Таким образом, кодировщику пришлось бы кодировать две условные ветви вместо одной, и пользователь мог бы увидеть больше вариантов поведения.
person Craig Hicks    schedule 04.01.2021