Проверяйте синхронно, если файл/каталог существует в Node.js

Как я могу синхронно проверять, используя node.js, если файл или каталог существует?

Ответ 1

Ответ на этот вопрос изменился за эти годы. Текущий ответ находится здесь вверху, за ним следуют различные ответы в хронологическом порядке:

Текущий ответ

Вы можете использовать fs.existsSync():

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

Это было объявлено устаревшим в течение нескольких лет, но больше не является. Из документов:

Обратите внимание, что fs.exists() устарела, а fs.existsSync() - нет. (Параметр обратного вызова для fs.exists() принимает параметры, которые несовместимы с другими обратными fs.existsSync() Node.js. fs.existsSync() не использует обратный вызов.)

Вы специально просили синхронную проверку, но если вместо этого вы можете использовать асинхронную проверку (обычно лучше всего с fs.promises.access/выводом), используйте fs.promises.access если вы используете async функции или fs.access (поскольку exists, устарело) если не:

В async функции:

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

Или с обратным вызовом:

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

Исторические ответы

Вот исторические ответы в хронологическом порядке:

  • Оригинальный ответ от 2010
    (stat/statSync или lstat/lstatSync)
  • Обновление сентябрь 2012
    (exists/exists existsSync)
  • Обновление февраль 2015
    (Принимая во внимание надвигающуюся устаревшую existsSync о exists/exists existsSync, поэтому мы, вероятно, вернулись к stat/statSync или lstat/lstatSync)
  • Обновление декабрь 2015
    (Там также fs.access(path, fs.F_OK, function(){})/fs.accessSync(path, fs.F_OK), но обратите внимание, что если файл/каталог не существует, это ошибка; документы для fs.stat рекомендует использовать fs.access если вам нужно проверить наличие, не открывая)
  • Обновление декабря 2016
    fs.exists() все еще не рекомендуется, но fs.existsSync() больше не рекомендуется. Таким образом, вы можете безопасно использовать его сейчас.

Оригинальный ответ от 2010 года:

Вы можете использовать statSync или lstatSync (ссылка на документацию), что дает вам объект fs.Stats. В целом, если доступна синхронная версия функции, она будет иметь то же имя, что и асинхронная версия с Sync в конце. Таким образом, statSync является синхронной версией stat; lstatSync - синхронная версия lstat и т.д.

lstatSync сообщает вам, существует ли что-то, и если да, то это файл или каталог (или в некоторых файловых системах, символьная ссылка, блочное устройство, символьное устройство и т.д.), например, если вам нужно знать, существует ли оно и это каталог:

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

... и аналогично, если это файл, есть isFile; если это блочное устройство, есть isBlockDevice и т.д. и т.д. Обратите внимание на try/catch; выдает ошибку, если запись вообще не существует.

Если вас не волнует, что это за запись, и вы хотите знать только, существует ли она, вы можете использовать path.existsSync (или с последним, fs.existsSync), как отмечено пользователем618408 :

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

Это не требует try/catch но не дает вам никакой информации о том, что это за штука, только то, что она есть. path.existsSync давно устарел.


Примечание: вы прямо спросили, как выполнять синхронную проверку, поэтому я использовал xyzSync версии функций xyzSync. Но там, где это возможно, с вводом/выводом лучше избегать синхронных вызовов. Вызовы в подсистему ввода/вывода занимают значительное время с точки зрения процессора. Обратите внимание, как просто вызвать lstat а не lstatSync:

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

Но если вам нужна синхронная версия, она там.

Обновление сентябрь 2012

Нижеприведенный ответ пару лет назад сейчас немного устарел. Текущий способ заключается в использовании fs.existsSync для синхронной проверки существования файла/каталога (или, конечно, fs.exists для асинхронной проверки), а не в path указанных ниже.

Пример:

var fs = require('fs');

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

// Or

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

Обновление февраль 2015

И вот мы находимся в 2015 году, и теперь документация по Node сообщает, что fs.existsSyncfs.exists) "будут устаревшими". (Потому что люди из Node думают, что глупо проверять, существует ли что-то, прежде чем открывать это, что это такое; но это не единственная причина для проверки, существует ли что-то!)

Таким образом, мы, вероятно, вернулись к различным методам stat... До тех пор, пока это не изменится, конечно.

Обновление декабрь 2015

Не знаю, как давно там, но есть также fs.access(path, fs.F_OK,...)/fs.accessSync(path, fs.F_OK). И, по крайней мере, по состоянию на октябрь 2016 года в документации fs.stat рекомендуется использовать fs.access для проверки существования ("Чтобы проверить, существует ли файл, не манипулируя им впоследствии, fs.access().). Но обратите внимание, что недоступность доступа считается ошибкой, поэтому, вероятно, будет лучше, если вы ожидаете, что файл будет доступен:

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

Обновление декабря 2016

Вы можете использовать fs.existsSync():

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

Это было объявлено устаревшим в течение нескольких лет, но больше не является. Из документов:

Обратите внимание, что fs.exists() устарела, а fs.existsSync() - нет. (Параметр обратного вызова для fs.exists() принимает параметры, которые несовместимы с другими обратными fs.existsSync() Node.js. fs.existsSync() не использует обратный вызов.)

Ответ 2

Глядя на источник, есть синхронная версия path.exists - path.existsSync. Похоже, это было пропущено в документах.

Обновить:

path.exists и path.existsSync теперь устарели. Пожалуйста, используйте fs.exists и fs.existsSync.

Обновление 2016:

fs.exists и fs.existsSync также устарели. Вместо этого используйте fs.stat() или fs.access().

Ответ 3

Используя рекомендуемые в настоящее время (по состоянию на 2015) API (в документе Node), это то, что я делаю:

var fs = require('fs');

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

В ответ на вопрос EPERM, поднятый @broadband в комментариях, это создает хороший момент. fileExists(), вероятно, не очень хороший способ подумать об этом во многих случаях, потому что fileExists() не может по-настоящему обещать логическое возвращение. Вы можете окончательно определить, что файл существует или не существует, но вы также можете получить ошибку разрешений. Ошибка разрешений не обязательно означает, что файл существует, потому что вам не хватает права на каталог, содержащий файл, на котором вы проверяете. И, конечно же, есть вероятность, что вы можете столкнуться с некоторой другой ошибкой при проверке существования файла.

Итак, мой код выше действительно делаетFileExistAndDoIHaveAccessToIt(), но ваш вопрос может быть hasFileNotExistAndCouldICreateIt(), который был бы совершенно другой логикой (для этого, кроме прочего, необходимо было бы учитывать ошибку EPERM).

В то время как ответ fs.existsSync обращается к прямому запросу, заданному здесь, это часто не будет тем, что вы хотите (вы не просто хотите знать, существует ли что-то "на пути", вам, вероятно, "вещь", которая существует, - это файл или каталог).

Суть в том, что если вы проверяете, существует ли файл, вы, вероятно, это делаете, потому что вы намереваетесь принять какое-то действие на основе результата, и эта логика (проверка и/или последующее действие) должна что идея, найденная на этом пути, может быть файлом или каталогом, и что вы можете столкнуться с EPERM или другими ошибками в процессе проверки.

Ответ 4

Другое обновление

Чтобы ответить на этот вопрос, я просмотрел документы node, кажется, что вы должны не использовать fs.exists, вместо этого используйте fs.open и используйте выводимую ошибку, чтобы определить, есть ли файл не существует:

из документов:

fs.exists() является анахронизмом и существует только по историческим причинам. В его собственном коде не должно быть причин использовать его.

В частности, проверка наличия файла перед его открытием анти-шаблон, который оставляет вас уязвимыми для условий гонки: другой процесс может удалить файл между вызовами fs.exists() и fs.open(). Просто откройте файл и обработайте ошибку, если она не есть.

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

Ответ 5

Я использую функцию ниже, чтобы проверить, существует ли файл. Он ловит и другие исключения. Таким образом, если есть проблемы с правами, например. chmod ugo-rwx filename или в Windows Функция Right Click -> Properties -> Security -> Advanced -> Permission entries: empty list .. возвращает исключение как следует. Файл существует, но у нас нет прав на его доступ. Было бы неправильно игнорировать такие исключения.

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

Исключение, документация ошибок nodejs в файле case не существует:

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

Исключение в случае, если у нас нет прав на файл, но существует:

{
  [Error: EPERM: operation not permitted, stat 'X:\file.txt']
  errno: -4048,
  code: 'EPERM',
  syscall: 'stat',
  path: 'X:\\file.txt'
}

Ответ 6

fs.exists() устарела, не используйте его https://nodejs.org/api/fs.html#fs_fs_exists_path_callback

Вы можете реализовать основной метод nodejs, используемый здесь: 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;
}

это вернет объект статистики, после того как вы получите объект статистики, вы можете попробовать

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

Ответ 7

В некоторых ответах говорится, что fs.exists и fs.existsSync обе устарели. Согласно документам, это не более верно. Теперь отменяется только fs.exists:

Обратите внимание, что fs.exists() устарел, но fs.existsSync() - нет. (The параметр обратного вызова в fs.exists() принимает параметры, которые несовместимы с другими обратными вызовами Node.js. fs.existsSync() не используйте обратный вызов.)

Таким образом, вы можете безопасно использовать fs.existsSync(), чтобы синхронно проверить, существует ли файл.

Ответ 8

Модуль path не предоставляет синхронную версию path.exists, поэтому вам нужно обмануть модуль fs.

Самая быстрая вещь, которую я могу себе представить, это использовать fs.realpathSync, которая выведет ошибку, которую вы должны поймать, поэтому вам нужно сделать свою собственную функцию-обертку с помощью try/catch.

Ответ 9

Использование тестов fileSystem (fs) приведет к возникновению объектов ошибки, которые затем вам нужно будет включить в оператор try/catch. Сохраните некоторые усилия и используйте функцию, представленную в ветке 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);
  });
});

Ответ 10

В документах fs.stat() говорится использовать fs.access(), если вы не собираетесь манипулировать файлом. Это не дает оправдания, может быть, быстрее или меньше использования memeory?

Я использую node для линейной автоматизации, поэтому я решил поделиться своей функцией, чтобы проверить существование файла.

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

Ответ 11

Вот простое оберточное решение для этого:

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

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

  • Работает как для каталогов, так и для файлов
  • Если элемент существует, он возвращает путь к файлу или каталогу
  • Если элемент не существует, он возвращает false

Пример:

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

Убедитесь, что вы используете === operator для проверки, если return равно false. Нет логической причины, что fs.realpathSync() вернет false при правильных рабочих условиях, поэтому я думаю, что это должно работать на 100%.

Я бы предпочел увидеть решение, которое не генерирует ошибку и результат производительности. С точки зрения API, fs.exists() кажется самым элегантным решением.

Ответ 12

обновленный asnwer для тех людей, "правильно" указывающих на то, что он не дает прямого ответа на вопрос, больше предлагает альтернативный вариант.

Синхронизация решения:

fs.existsSync('filePath') также см. здесь.

Возвращает true, если путь существует, иначе false.

Решение Async Promise

В асинхронном контексте вы можете просто написать асинхронную версию в методе синхронизации с помощью ключевого слова await. Вы можете просто превратить асинхронный метод обратного вызова в обещание, подобное этому:

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

документы по доступу().

Ответ 13

Из ответов видно, что для этого нет официальной поддержки API (как при прямой и явной проверке). Многие из ответов говорят использовать stat, однако они не являются строгими. Мы не можем предположить, например, что любая ошибка, выдаваемая stat, означает, что что-то не существует.

Допустим, мы попробуем это с чем-то, что не существует:

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

Давайте попробуем это с чем-то, что существует, но у нас нет доступа к:

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

По крайней мере, вы захотите:

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

Вопрос не ясен, если вы действительно хотите, чтобы он был синхронным, или если вы хотите, чтобы он был записан так, как если бы он был синхронным. В этом примере используется await/async, поэтому он записывается только синхронно, но работает асинхронно.

Это означает, что вы должны называть это так на верхнем уровне:

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

В качестве альтернативы можно использовать .then и .catch для обещания, возвращаемого асинхронным вызовом, если оно понадобится вам в дальнейшем.

Если вы хотите проверить, существует ли что-то, то хорошей практикой также является обеспечение правильного типа вещи, такой как каталог или файл. Это включено в пример. Если не разрешено быть символической ссылкой, вы должны использовать lstat вместо stat, так как stat будет автоматически проходить по ссылкам.

Вы можете заменить весь асинхронный код для синхронизации здесь и использовать вместо него statSync. Однако следует ожидать, что как только асинхронность и ожидание станут повсеместно поддерживаемыми, вызовы Sync со временем станут избыточными и будут обесцениваться (в противном случае вам придется определять их везде и по всей цепочке, как в случае с асинхронностью, что делает ее действительно бессмысленной).