简体   繁体   English

Node.js 检查文件是否存在

[英]Node.js check if file exists

How do I check for the existence of a file?如何检查文件是否存在?

Consider opening the file directly, to avoid race conditions:考虑直接打开文件,以避免竞争条件:

const fs = require('fs');

fs.open('foo.txt', 'r', function (err, fd) {
  // ...
});

Using fs.existsSync :使用fs.existsSync

if (fs.existsSync('foo.txt')) {
  // ...
}

Using fs.stat :使用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);
  }
});

Deprecated:已弃用:

fs.exists is deprecated. fs.exists已弃用。

Using path.exists :使用path.exists

const path = require('path');

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

Using path.existsSync :使用path.existsSync

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

Edit: Since node v10.0.0 we could use fs.promises.access(...)编辑:由于节点v10.0.0我们可以使用fs.promises.access(...)

Example async code that checks if file exists:检查文件是否存在的示例异步代码:

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

An alternative for stat might be using the new fs.access(...) : stat 的替代方法可能是使用新的fs.access(...)

minified short promise function for checking:用于检查的缩小的短承诺功能:

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

Sample usage:示例用法:

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

expanded Promise way:扩展承诺方式:

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

or if you wanna do it synchronously:或者如果你想同步做:

function checkFileExistsSync(filepath){
  let flag = true;
  try{
    fs.accessSync(filepath, fs.constants.F_OK);
  }catch(e){
    flag = false;
  }
  return flag;
}

A easier way to do this synchronously.同步执行此操作的更简单方法。

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

The API doc says how existsSync work: API 文档说明了existsSync的工作原理:
Test whether or not the given path exists by checking with the file system.通过检查文件系统来测试给定路径是否存在。

Modern async/await way ( Node 12.8.x )现代异步/等待方式(节点 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();

We need to use fs.stat() or fs.access() because fs.exists(path, callback) now is deprecated我们需要使用fs.stat() or fs.access()因为fs.exists(path, callback)现在已被弃用

Another good way is fs-extra另一个好方法是fs-extra

fs.exists(path, callback) and fs.existsSync(path) are deprecated now, see https://nodejs.org/api/fs.html#fs_fs_exists_path_callback and https://nodejs.org/api/fs.html#fs_fs_existssync_path . fs.exists(path, callback)fs.existsSync(path)现在已弃用,请参阅https://nodejs.org/api/fs.html#fs_fs_exists_path_callbackhttps://nodejs.org/api/fs.html# fs_fs_existssync_path

To test the existence of a file synchronously one can use ie.要同步测试文件的存在,可以使用 ie。 fs.statSync(path) . fs.statSync(path) An fs.Stats object will be returned if the file exists, see https://nodejs.org/api/fs.html#fs_class_fs_stats , otherwise an error is thrown which will be catched by the try / catch statement.如果文件存在,将返回一个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.");
}

Old Version before V6: here's the documentation 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');
  }

UPDATE更新

New versions from V6: documentation for fs.stat V6 的新版本: fs.stat的文档

fs.stat('/etc/passwd', function(err, stat) {
    if(err == null) {
        //Exist
    } else if(err.code == 'ENOENT') {
        // NO exist
    } 
});

Aug 2021 2021 年 8 月

After reading all posts:看完所有帖子后:

let filePath = "./directory1/file1.txt";

if (fs.existsSync(filePath)) {
    console.log("The file exists");
} else {
    console.log("The file does not exist");
}

There are a lot of inaccurate comments about fs.existsSync() being deprecated;有很多关于fs.existsSync()被弃用的不准确评论; it is not.它不是。

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

Note that fs.exists() is deprecated, but fs.existsSync() is not.请注意,不推荐使用 fs.exists(),但不推荐使用 fs.existsSync()。

@Fox: great answer! @Fox:很好的答案! Here's a bit of an extension with some more options.这是一个带有更多选项的扩展。 It's what I've been using lately as a go-to solution:这是我最近一直使用的首选解决方案:

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


}

PS check out fs-extra if you aren't already using it-- it's pretty sweet. PS 如果您还没有使用它,请查看 fs-extra——它非常棒。 https://github.com/jprichardson/node-fs-extra ) https://github.com/jprichardson/node-fs-extra

fs.exists has been deprecated since 1.0.0. fs.exists自 1.0.0 起已被弃用。 You can use fs.stat instead of that.您可以使用fs.stat来代替。

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

Here is the link for the documentation fs.stats这是文档fs.stats的链接

async/await version using util.promisify as of Node 8:从 Node 8 开始使用util.promisifyasync/await版本:

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

A concise solution in async await style:异步等待风格的简洁解决方案:

import { stat } from 'fs/promises';

const exists = await stat('foo.txt')
   .then(() => true)
   .catch(() => false);

  fs.statSync(path, function(err, stat){
      if(err == null) {
          console.log('File exists');
          //code when all ok
      }else if (err.code == "ENOENT") {
        //file doesn't exist
        console.log('not file');

      }
      else {
        console.log('Some other error: ', err.code);
      }
    });

After a bit of experimentation, I found the following example using fs.stat to be a good way to asynchronously check whether a file exists.经过一番实验,我发现以下使用fs.stat的示例是异步检查文件是否存在的好方法。 It also checks that your "file" is "really-is-a-file" (and not a directory).它还会检查您的“文件”是否是“真正的文件”(而不是目录)。

This method uses Promises, assuming that you are working with an asynchronous codebase:此方法使用 Promises,假设您正在使用异步代码库:

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

If the file does not exist, the promise still resolves, albeit false .如果文件不存在,promise 仍然会解析,尽管是false If the file does exist, and it is a directory, then is resolves true .如果文件确实存在,并且它是一个目录,那么 is 解析为true Any errors attempting to read the file will reject the promise the error itself.任何试图读取文件的错误都会reject错误本身的承诺。

Well I did it this way, as seen on https://nodejs.org/api/fs.html#fs_fs_access_path_mode_callback好吧,我是这样做的,如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');
  }
});

Is there any problem with this?这有什么问题吗?

Using typescript and fs/promises in node14在 node14 中使用 typescript 和 fs/promises

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

It is better to use fsp.readFile than fsp.stat or fsp.access for two reasons:使用fsp.readFile比使用fsp.statfsp.access更好,原因有二:

  1. The least important reason - it is one less access.最不重要的原因 - 它是一个少访问。
  2. It is possible that fsp.stat and fsp.readFile would give different answers. fsp.statfsp.readFile可能会给出不同的答案。 Either due to subtle differences in the questions they ask, or because the files status changed between the calls.要么是由于他们提出的问题存在细微差别,要么是因为文件状态在通话之间发生了变化。 So the coder would have to code for two conditional branches instead of one, and the user might see more behaviors.因此,编码人员必须编写两个条件分支而不是一个,用户可能会看到更多行为。

in old days before sit down I always check if chair is there then I sit else I have an alternative plan like sit on a coach.在过去,在坐下之前,我总是检查椅子是否在那里,然后我就坐,否则我有一个替代计划,比如坐在教练上。 Now node.js site suggest just go (no needs to check) and the answer looks like this:现在 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 );
    } );

code taken from http://fredkschott.com/post/2014/03/understanding-error-first-callbacks-in-node-js/ from March 2014, and slightly modified to fit computer.代码取自 2014 年 3 月的http://fredkschott.com/post/2014/03/understanding-error-first-callbacks-in-node-js/ ,稍作修改以适应计算机。 It checks for permission as well - remove permission for to test chmod ar foo.txt它也会检查权限 - 删除测试chmod ar foo.txt的权限

vannilla Nodejs callback香草 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.
}

the docs say you should use access() as a replacement for deprecated exists()文档说您应该使用access()代替不推荐使用的exists()

Nodejs with build in promise (node 7+)具有内置承诺的 Nodejs(节点 7+)

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

Popular javascript framework流行的javascript框架

fs-extra fs-额外

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

As you see much simpler.如您所见,要简单得多。 And the advantage over promisify is that you have complete typings with this package (complete intellisense/typescript)!与 promisify 相比的优势在于,您可以使用这个包进行完整的输入(完整的智能感知/打字稿)! Most of the cases you will have already included this library because (+-10.000) other libraries depend on it.大多数情况下,您已经包含了这个库,因为 (+-10.000) 其他库依赖于它。

You can use fs.stat to check if target is a file or directory and you can use fs.access to check if you can write/read/execute the file.您可以使用fs.stat检查目标是文件还是目录,并且可以使用fs.access检查是否可以写入/读取/执行文件。 (remember to use path.resolve to get full path for the target) (记得使用path.resolve来获取目标的完整路径)

Documentation:文档:

Full example (TypeScript)完整示例(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);
}());

For asynchronous version!对于异步版本! And with the promise version!并带有承诺版本! Here the clean simple way!这里是干净简单的方法!

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

A more practical snippet from my code to illustrate better:我的代码中更实用的片段可以更好地说明:


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

The example above is just for demonstration!上面的例子只是为了演示! I could have used the error event of the read stream!我本可以使用读取流的错误事件! To catch any errors!捕捉任何错误! And skip the two calls!跳过这两个电话!

For those who ❤️ async-await对于那些 ❤️ async-await 的人

import fsp from 'fs/promises';

async function isFileExist(path) {
    try {
        return (await fsp.stat(path)).isFile();
    } catch (e) {
        return false;
    }
}

const path = './dir/file.pdf';
console.log(await isFileExist(path));

Using Promise使用 Promise

import { existsSync } from 'fs'

const exists = (filepath) => new Promise((res) => {
  existsSync(filepath) ? res(true) : res(false)
})

// Usage #1 (async/await)
const doesItExist = await exists('foo.txt')
if (doesItExist == false) {
  // create the file
}

// Usage #2 (thenable)
exists('foo.txt').then(doesItExist => {
  if (!doesItExist) {
    // create file
  }
})

But honestly it's rare to have a case like that,但老实说,这种情况很少见,
Usually you'll just go with通常你只需要 go

import { existsSync as exists } from 'fs'

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM