Node.js检查文件是否存在

如何检查文件是否存在?

348492 次浏览

考虑直接打开或读取文件,以避免竞争条件:

const fs = require('fs');


fs.open('foo.txt', 'r', (err, fd) => {
// ...
});
fs.readFile('foo.txt', (err, data) => {
if (!err && data) {
// ...
}
})


使用fs.existsSync:

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

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

弃用:

fs.exists已弃用。

使用path.exists:

const path = require('path');


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

使用path.existsSync:

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

@狐狸:好答案! 这里有一个扩展,有更多的选项。

是我最近一直在使用的解决方案
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 >注:如果你还没有用过fs-extra,那就试试吧——它真的很贴心。 https://github.com/jprichardson/node-fs-extra) < / p >

一种更简单的同步方法。

if (fs.existsSync('/etc/file')) {
console.log('Found file');
}
API文档说明existsSync是如何工作的 .使用文件系统检查指定路径是否存在

以前,在坐下之前,我总是检查一下椅子是否在那里,然后再坐下,否则我有一个替代计划,比如坐在教练上。现在node.js站点建议直接go(不需要检查),答案是这样的:

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

代码取自2014年3月的http://fredkschott.com/post/2014/03/understanding-error-first-callbacks-in-node-js/,并进行了轻微修改以适合计算机。它也检查权限-删除测试chmod a-r foo.txt的权限

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

要同步测试一个文件是否存在,可以使用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.");
}

<强>编辑: 因为节点v10.0.0we可以使用fs.promises.access(...)

检查文件是否存在的异步代码示例:

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

stat的替代方法可能是使用新的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;
}

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 < / p >

我是这样做的,如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');
}
});

这有什么问题吗?

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

V6之前的旧版本: 下面是文档 < / p >

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

经过一些实验,我发现下面的例子使用fs.stat是异步检查文件是否存在的好方法。它还检查您的“文件”是否“真的是一个文件”(而不是一个目录)。

这个方法使用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);
}
});
};

如果文件不存在,promise仍然解析,尽管false。如果文件确实存在,并且它是一个目录,那么is解析true。任何试图读取文件的错误将reject承诺错误本身。

vannilla 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 (node 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相比,它的优势在于你可以使用这个包实现完整的类型(完整的智能感知/typescript)!大多数情况下,您已经包含了这个库,因为(+-10.000)其他库都依赖于它。

有很多关于fs.existsSync()被弃用的不准确的评论;事实并非如此。

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

注意fs.exists()已弃用,但fs.existsSync()未弃用。

在节点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);
}
});
});

你可以使用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);
}());

现代异步/等待方式(Node 12.8. net)。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

异步版本!还有承诺版本!这里有干净简单的方法!

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

上面的例子只是为了演示!我可以使用读流的错误事件!捕捉任何错误!跳过这两个电话!

在node14中使用typescript和fs/promises

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

使用fsp.readFile比使用__abc1或fsp.access更好,原因有两个:

  1. 最不重要的原因是少了一个机会。
  2. __abc0和fsp.readFile可能会给出不同的答案。要么是因为他们所问问题的细微差异,要么是因为文件状态在两次调用之间发生了变化。因此编码器必须为两个而不是一个条件分支编码,用户可能会看到更多的行为。

2021年8月

读完所有帖子后:

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


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

异步等待风格的简洁解决方案:

import { stat } from 'fs/promises';


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