Node.jsにファイル/ディレクトリが存在するかどうかを同期的にチェックします


1209

ファイルまたはディレクトリが存在するかどうかをnode.jsを使用して同期的に確認するにはどうすればよいですか?


58
同期操作は、モジュールを返す前に1回限りのファイル/ディレクトリ操作を実行するのに最適です。たとえば、構成ファイルをブートストラップします。
jocull

1
ウォームキャッシュを使用した @PaulDraper は、すべての場合に当てはまるわけではありません。
mikemaccana 2017

12
パフォーマンスに関係なく、場合によっては、開発者エクスペリエンスのために同期方法で実行したいだけです。たとえば、設計上ブロックする必要があるデータ処理スクリプトにNodeを使用している場合、その場合、非同期existsは不要なコールバックを追加するだけです。
Kunok

3
クノックの発言に間違いなく+1。残りのコードでは、速度が本当に重要なボトルネックである場合にのみ、コードをより複雑にします。その原則をファイルの読み取りに適用しないのはなぜですか?多くのプログラムの多くの部分で、コードの単純性/読みやすさは実行速度よりも重要です。それがボトルネック領域である場合は、非同期メソッドを使用して、以降のコード実行を停止しないようにします。そうでなければ...同期は素晴らしいです。盲目的に同期を憎むな。
BryanGrezeszak

3
ユーザーは同期的にそれを行う方法を明示的に要求するため、「注意する価値はありません」。
jClark 2018年

回答:


2241

この質問への答えは、長年にわたって変化しました。現在答えは、時系列順に長年にわたって様々な答えが続き、最上部にここにあります:

現在の回答

使用できます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()他のNode.jsコールバックと矛盾するパラメーターを受け入れるためのコールバックパラメーター。コールバックfs.existsSync()は使用しません。)

特に同期チェックを要求しましたが、代わりに非同期チェックを使用できる場合(通常はI / Oで最適)、関数を使用している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年9月の更新
    exists/existsSync
  • 2015年2月更新
    exists/の廃止が差し迫っていることexistsSyncに注意して、おそらくstat/ statSyncまたはlstat/lstatSync
  • 2015年12月更新
    fs.access(path, fs.F_OK, function(){})/ もありfs.accessSync(path, fs.F_OK)ますが、ファイル/ディレクトリが存在しない場合はエラーです。開くことなく存在を確認する必要がある場合にfs.stat使用fs.accessすることをお勧めします)
  • 2016年12月のアップデート
    fs.exists()は引き続き非推奨ですが、非推奨でfs.existsSync()はなくなりました。安全に使用できるようになりました。

2010年の元の回答:

statSyncまたはlstatSyncドキュメントリンク)を使用して、fs.Statsオブジェクトを取得できます。一般に、関数の同期バージョンが使用可能な場合、関数の名前は非同期バージョンと同じ名前になりSync、最後に付きます。だから、statSyncの同期バージョンですstatlstatSyncの同期バージョン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ます。エントリがまったく存在しない場合は、エラーがスローされます。

エントリ何であるかを気にせず、それが存在するかどうかを知りたいだけの場合は、user618408によって指摘されているようにpath.existsSync(またはlatestでfs.existsSync)使用できます。

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

aは必要ありませんがtry/catch、物があるかどうかについての情報はありません。 path.existsSyncずっと前に廃止されました。


補足:同期的にチェックする方法を明確に尋ねたのでxyzSync、上記の関数のバージョンを使用しました。ただし、I / Oを使用する場合は、可能な限り同期呼び出しを回避するのが最善です。I / Oサブシステムへの呼び出しには、CPUの観点からかなりの時間がかかります。呼び出すのlstatではなく、呼び出しがいかに簡単であるかに注意してくださいlstatSync

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

しかし、同期バージョンが必要な場合は、そこにあります。

2012年9月更新

数年前の以下の回答は少し古くなっています。現在の方法は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年2月の更新

そしてここに私たちは2015年にいて、Nodeドキュメントは今それを言っていますfs.existsSync(そしてfs.exists)「廃止される」とます。(Nodeの人々は、開く前に何かが存在するかどうかを確認するのは馬鹿げていると思うので、それはそうです。しかし、それが何かが存在するかどうかを確認する唯一の理由ではありません!)

ですから、私たちはおそらくさまざまなstat方法に戻っています...もちろん、これが再び変わるまでは/もちろんです。

2015年12月の更新

そこにどれくらいの時間があったかわからないが、fs.access(path, fs.F_OK, ...)/fs.accessSync(path, fs.F_OK)もある。そして、少なくとも2016年10月現在、この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年12月の更新

使用できますfs.existsSync()

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

それは数年間廃止されましたが、現在は廃止されていません。ドキュメントから:

fs.exists()非推奨されますが、fs.existsSync()ではありません。(fs.exists()他のNode.jsコールバックと矛盾するパラメーターを受け入れるためのコールバックパラメーター。コールバックfs.existsSync()は使用しません。)


7
path.existsとpath.existsSync両方がfs.existsとfs.existsSyncの賛成で廃止されました
ドリュー

15
「ノードの人々はそれを開く前に何かが存在するかどうかをチェックするのは馬鹿げていると思っています。ファイルが存在するかどうかを確認するのが難しいのはなぜですか?
Petr Hurtak

32
@PetrHurtak:常に存在するとは限りませ(存在を確認する理由はたくさんあるため)。ただし、ファイルを開く場合は、open呼び出しを発行して例外を処理するか、ファイルが存在しない場合は何でも処理することをお勧めします。見つかりました。結局のところ、現実の世界は無秩序です。最初に確認してそこにあるとしても、それを開こうとしたときにまだそこにあるわけではありません。最初に確認してもそこにない場合でも、それがすぐになくなるわけではありません。このようなタイミングはエッジケースのように見えますが、常に発生します。したがって開く場合は、最初にチェックしても意味がありません。
TJクラウダー

13
そしてここで、制御フローにエラーを使用するのはアンチパターンだと思いました: link
argyle

4
@jeromeyers:できますが、Ionică がすでに行っています上記のコメントを参照)。:-)
TJクラウダー2015

124

ソースを見ると、同期バージョンのpath.exists-がありpath.existsSyncます。ドキュメントで見逃されたようです。

更新:

path.existsそしてpath.existsSync今されている非推奨使用してくださいfs.existsfs.existsSync

2016年更新:

fs.exists そしてfs.existsSyncまた 非難されました。代わりにfs.stat()またはfs.access()を使用してください。

アップデート2019:

使用しますfs.existsSync。非推奨ではありません。 https://nodejs.org/api/fs.html#fs_fs_existssync_path


1
path.existsSync(p)は0.4.10のドキュメントにありますnodejs.org/docs/v0.4.10/api/path.html
Paul Beusterien

21
実際、より最近の回答:path.existsSyncは非推奨になりました。現在はと呼ばれていfs.existsSyncます。
Olivier Lalonde、2012年

9
今、ドキュメントはfs.existsが廃止されると言っています。nodejs.org/api/fs.html#fs_fs_existssync_path
Greg Hornby

私は古い置き換えるために少しライブラリを書いたexists:機能is-there
IonicăBizău

6
現在のドキュメント(バージョン〜9)はfs.exists非推奨としてのみラベル付けされてfs.existsSyncいますが、そうではありません!
Kunok

57

(ノードのドキュメントごとに)現在推奨されている(2015年の)APIを使用して、これは私が行うことです:

var fs = require('fs');

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

コメントで@broadbandによって提起されたEPERM問題に対応して、それは良い点をもたらします。fileExists()はブール値の戻りを実際に約束できないため、fileExists()はおそらく多くの場合、これについて考える良い方法ではありません。ファイルが存在するか存在しないかを明確に判断できる場合がありますが、アクセス権エラーが発生する場合もあります。確認するファイルを含むディレクトリへのアクセス許可が不足している可能性があるため、アクセス許可エラーは必ずしもファイルが存在することを意味するわけではありません。もちろん、ファイルの存在を確認する際に他のエラーが発生する可能性もあります。

したがって、上のコードは本当にdoesFileExistAndDoIHaveAccessToIt()ですが、質問はdoesFileNotExistAndCouldICreateIt()かもしれません。これは完全に異なるロジック(特にEPERMエラーを説明する必要がある)です。

fs.existsSync回答は、ここで直接尋ねられた質問に対処しますが、それはしばしばあなたが望むものではありません(「何か」がパスに存在するかどうかを知りたいだけではなく、おそらく「もの」が存在するのはファイルまたはディレクトリです)。

肝心な点は、ファイルが存在するかどうかを確認する場合、結果に基づいて何らかのアクションを実行するつもりであり、そのロジック(チェックおよび/または後続のアクション)がアイデアに対応する必要があるためです。そのパスで見つかったものがファイルまたはディレクトリである可能性があること、およびチェックの過程でEPERMまたはその他のエラーが発生する可能性があること。


4
いいですね、|| isDirectory()を使用してファイル/フォルダーチェッカーにします。var stats = fs.statSync(filePath); return stats.isFile()|| stats.isDirectory();
ボブ

4
プログラムがファイルにアクセスする権限を持っていない場合、ファイルが存在しても、falseを返します。つまり、ファイルchmod ugo-rwx file.txtからすべてのリグを削除するか、Windowsで右クリックします。例外メッセージ:Exception fs.statSync(./ f.txt):エラー:EPERM:操作は許可されていません、統計 'X:\ f.txt'。したがって、このケースは上位のコードではカバーされていません。
ブロードバンド

2
うわー、JSは時々遅れています。確かに、ファイルを使用する時間は97%ですがfile.exists()、3%の単純なユーティリティがなく、代わりにこれをトライキャッチでラップする必要がありますか?本当のことを...今日のビッチ。
追放された

20

別のアップデート

私自身、ノードのドキュメントを調べて、この質問への回答が必要です。 場合、fs.existsを使用なく、代わりにfs.openを使用して、出力されたエラーを使用して、ファイルが存在しないかどうかを検出します。

ドキュメントから:

fs.exists()は時代遅れであり、歴史的な理由でのみ存在します。独自のコードで使用する理由はほとんどありません。

特に、開く前にファイルが存在するかどうかを確認することは、競合状態に対して脆弱なアンチパターンであり、別のプロセスがfs.exists()とfs.open()の呼び出しの間にファイルを削除する可能性があります。ファイルを開いて、そこにないときにエラーを処理するだけです。

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


1
openではなくopenSyncでそれを行う方法はありますか
Greg Hornby

1
@GregHornby openSyncでも同じように機能するはずだと思います
Melbourne2991

2
まだ必要とする人のためにexistsexistsSync、私が作成しましたis-there
IonicăBizău

6
この非難は私を悩ませます。エラーがスローされたかどうかを確認するためだけにファイルを開くことは、必要なのがファイルの存在の知識だけである場合、リソースの無駄のように見えます。
Josh Hansen

11

以下の関数を使用して、ファイルが存在するかどうかをテストします。他の例外もキャッチします。したがって、たとえばchmod ugo-rwx filenameWindowsで権利の問題がある場合、 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エラードキュメント

{
  [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'
}

2
本当にこのように、それは、ノードがこれを行うための最後の37個の方法を推奨していませんので、最新の状態にありますいくつかの答えの一つだ
1mike12

ああ、あなたは私をそれに打ち負かした。これを読んだら、時間を節約できただろう。
jgmjgm 2017年

5

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

これはstatsオブジェクトを返し、statsオブジェクトを取得したら、試すことができます

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

4

ここでいくつかの回答はそれfs.existsを言い、fs.existsSync両方とも非推奨です。ドキュメントによると、これは真実ではありません。fs.exists今は欠けているだけです:

fs.exists()は非推奨ですが、fs.existsSync()は非推奨です。(fs.exists()へのコールバックパラメータは、他のNode.jsコールバックと矛盾するパラメータを受け入れます。fs.existsSync()はコールバックを使用しません。)

したがって、fs.existsSync()を安全に使用して、ファイルが存在するかどうかを同期的にチェックできます。


3

pathモジュールは、同期のバージョン提供していないpath.existsあなたと周りだまして持っているので、fsモジュールを。

私が想像できる最も速いことはfs.realpathSync、あなたがキャッチしなければならないエラーを投げるので、try / catchであなた自身のラッパー関数を作る必要があるということです。


1

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

2
path.existsはfsの下にあるので、fs.exists(path、callback)になります
Todd Moses

0

上のドキュメントfs.stat()は使用するように言いますfs.access()、ファイルを操作しない場合ようにいます。それは正当化を与えませんでした、より速いか少ない記憶の使用かもしれません?

私は線形自動化にノードを使用しているので、ファイルの存在をテストするために使用する関数を共有すると思いました。

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

0

それが質問に直接答えないことを「正しく」指摘する人々のための更新された回答は、より多くの代替オプションをもたらします。

同期ソリューション:

fs.existsSync('filePath')こちらのドキュメントご覧ください

パスが存在する場合はtrueを返し、それ以外の場合はfalseを返します。

非同期プロミスソリューション

非同期コンテキストでは、awaitキーワードを使用して、非同期バージョンの同期メソッドを記述するだけです。単純に非同期コールバックメソッドを次のようなpromiseに変換できます。

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

access()に関するドキュメント


1
OPは同期ソリューションを求めています
vdegenne

次のようにコードを更新する必要がありますfunction 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

おそらく、ファイルが存在するかどうかを知りたい場合は、存在する場合にそれを要求することを計画しています。

function getFile(path){
    try{
        return require(path);
    }catch(e){
        return false;
    }
}

-1

これは、このための簡単なラッパーソリューションです。

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

===演算子を使用して、戻り値がfalseかどうかをテストしてください。fs.realpathSync()が適切な動作条件下でfalseを返す論理的な理由はないので、これは100%動作するはずです。

エラーが発生せず、結果としてパフォーマンスが低下しないソリューションが欲しいです。APIの観点から見ると、fs.exists()は最もエレガントなソリューションのようです。


1
@ダン、ありがとう。切り捨てられたテキストを削除しました。そのメモが何だったか思い出せない。私が来たら、メモを追加します。
Timothy C. Quinn

1
Np。コメントを削除します。
Dan Dascalescu、2015年

-2

回答から、これに対する公式の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);
    }
})();

もう1つの方法は、必要に応じて、非同期呼び出しから返されたpromiseで.thenと.catchを使用することです。

何かが存在するかどうかを確認する場合は、それがディレクトリやファイルなどの適切なタイプであることを確認することもお勧めします。これは例に含まれています。シンボリックリンクにすることが許可されていない場合は、statが自動的にリンクをトラバースするため、statではなくlstatを使用する必要があります。

すべての非同期を置き換えて、ここでコードを同期し、代わりにstatSyncを使用できます。ただし、非同期で待機すると普遍的にサポートされるようになると予想されます。同期呼び出しは最終的には冗長になるため、減価償却されます。


1
元の質問はそれを指定していません。私は明確に物事を行う方法も示しています。多くの回答は、明確さの欠如のためにバグを引き起こす可能性があります。多くの場合、同期的に見えるようにプログラムすることを望みますが、必ずしも同期実行を望んでいるわけではありません。statSyncは、私がデモしたコードと同じではありません。実際に何を望んでいるかのどちらの説明も曖昧なので、個人的な解釈を課すだけです。わからない回答を見つけた場合は、コメントまたはPMに尋ねて、必要な編集を検討することをお勧めします。
jgmjgm

1
必要に応じて、コードサンプルを盗み、適切な名前を付け、githubに配置してnpmに追加すると、答えは1行/リンクのみになります:D。
jgmjgm 2018

コードは例としては短いものですが、&&!isFileやシンボリックリンクのチェックなどを含めるための編集提案を送信することを歓迎します(この場合も、質問がそれが望んでいることを明示的に述べていることはありません)。私がすでに指摘したように、私の答えは質問の1つの解釈を満たし、あなたの1行の提案が行うのと同じことを行いません。
jgmjgm
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.