LoginSignup
5

More than 1 year has passed since last update.

no such file or directory, open の理由を知る

Last updated at Posted at 2020-10-08

fsを使用して、上のディレクトリのファイルを取得しようとするとError: ENOENT: no such file or directory, open が出て、喚いていたが解決したので残しておく。
既知の事実と言ってはいけない。

ファイル内容

先に記しておくが、後の説明を読みながら解釈することを勧める。

ディレクトリ構成
test(親ディレクトリ)
   ├── src
   │   └── fileManeger.js
   ├── config ←(ここに出力)
   │     
   └── main.js

main.js
const fs = require('fs'); //nodeモジュール読みこみ
const fileManegerClass = require('./src/fileManeger.js') //クラスファイル読みこみ
const fileManeger = new fileManegerClass();  //インスタンス化

const content = {"name" : "taro" , "age" : 30};

//fsを引数から受け取る 相対パスをmain.jsがあるディレクトリからに
    fileManeger.write1(content, fs);

//fsをメソッド内でインポート 相対パスをmain.jsがあるディレクトリからに
    fileManeger.write2(content);

//fsを引数から受け取る 相対パスをfileManeger.jsがあるディレクトリからに
    fileManeger.write3(content, fs);

//fsをメソッド内でインポート 相対パスをfileManeger.jsがあるディレクトリからに
    fileManeger.write4(content);
fileManeger.js
class fileManeger {

    //fsを引数から受け取る 相対パスをmain.jsがあるディレクトリからに
    async write1 (content,fs){
        try{
            fs.writeFileSync('./config/write-1.json', JSON.stringify(content, null, "\t"),'utf8');
            console.log(`write1 complete`);
        }catch(e){
            console.log(`write1 fail\n${e}\n-------------------------------\n`);
        };
    };

    //fsをメソッド内でインポート 相対パスをmain.jsがあるディレクトリからに
    async write2 (content) {
        const fs = require('fs');
        try{
            fs.writeFileSync('./config/write-2.json', JSON.stringify(content, null, "\t"),'utf8');
            console.log(`write2 complete`);
        }catch(e){
            console.log(`write2 fail\n${e}\n-------------------------------\n`);
        };
    };

    //fsを引数から受け取る 相対パスをfileManeger.jsがあるディレクトリからに
    async write3 (content,fs) {
        try{
            fs.writeFileSync('../config/write-3.json', JSON.stringify(content, null, "\t"),'utf8');
            console.log(`write3 complete`);
        }catch(e){
            console.log(`write3 fail\n${e}\n-------------------------------\n`);
        };
    };
    //fsをメソッド内でインポート 相対パスをfileManeger.jsがあるディレクトリからに
    async write4 (content) {
        const fs = require('fs');
        try{
            fs.writeFileSync('../config/write-4.json', JSON.stringify(content, null, "\t"),'utf8');
            console.log(`write4 complete`);
        }catch(e){
            console.log(`write4 fail\n${e}\n-------------------------------\n`);
        };
    };
};
module.exports = fileManeger; //クラス出力

やりたいこと

main.jsから./src/fileManeger.js(クラス)を読み込み、configディレクトリ内にファイルを出力する。

はまった理由

結論から言うと、fsのパスの指定の仕方が悪かった。私は最初、fileManeger.jsでfsは呼び出されるのだからパスはそのファイルからたどるのだろうと勝手に推測して../config/write.jsonと指定していた。
しかしながら、fsはパスを作業ディレクトリからたどる。ここでいう作業ディレクトリとはnodeで実行したファイルがあるディレクトリのこと、つまりtestディレクトリである。
ということは私が指定したディレクトリはtestディレクトリの上層にあることになってしまっていたのだ。


│
├──config(???? 幻のディレクトリ)
│
└──test(ここから ../config/write.json)
      ├── src
      │   └── fileManeger.js
      ├── config ←(ここを指定したはずが...)
      │     
      └── main.js

試してみた

testディレクトリでmain.jsを実行する。
比較のため、fsモジュールの読み込み箇所と出力ファイル名、パスを変えている。
一応、モジュールをインポートする場所は関係ないことを示すために4つのパターンを用意した。

メソッド名 パス モジュールの読み込み 出力ファイル名
write1 ./config/write-1.json 引数から write-1.json
write2 ./config/write-2.json メソッド内で write-2.json
write3 ../config/write-3.json 引数から write-3.json
write4 ../config/write-4.json メソッド内で write-4.json

実行結果

console.png

./config/write-〇.jsonのパスであるwrite1メソッドとwrite2メソッドは成功している。
一方、../config/write-〇.jsonのパスであるwrite3メソッドとwrite4メソッドは読み込めないとエラーが出ている。

ファイルもwrite-1.jsonwrite-2.jsonのみ出力されている。
output.png

結論

以上のことから、fsのファイルパスの起点はnode.jsで実行しているファイルがあるディレクトリであることがわかった

よって、fsを使用したコードのエラーでError: ENOENT: no such file or directory, openが出た際は、ファイルのパスがnode.jsで実行しているファイルがあるディレクトリからの相対パスになっているか確認しよう

参考

公式ドキュメントにファイルパスの話が出ているのでその部分のリンクを記載しておく。
Node.js v14.13.1 Documentation

検証に使用したソースコード
github huda0209/qiita_fs-sample

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
5