fsを使用して、上のディレクトリのファイルを取得しようとするとError: ENOENT: no such file or directory, open が出て、喚いていたが解決したので残しておく。
ファイル内容
先に記しておくが、後の説明を読みながら解釈することを勧める。
ディレクトリ構成
test(親ディレクトリ)
├── src
│ └── fileManeger.js
├── config ←(ここに出力)
│
└── main.js
main.js
constfs=require('fs');//nodeモジュール読みこみconstfileManegerClass=require('./src/fileManeger.js')//クラスファイル読みこみconstfileManeger=newfileManegerClass(fs);//インスタンス化constcontent={"name":"taro","age":30};fileManeger.write1(content);//fsをメソッド内でインポートする ファイルの相対パスをmain.jsがあるディレクトリからにするfileManeger.write2(content);//fsをメソッド内でインポートする ファイルの相対パスをmain.jsがあるディレクトリからにするfileManeger.write3(content);//fsをコンストラクタから受け取る ファイルの相対パスをfileManeger.jsがあるディレクトリからにするfileManeger.write4(content);//fsをメソッド内でインポートする ファイルの相対パスをfileManeger.jsがあるディレクトリからにする
fileManeger.js
classfileManeger{constructor(fs){this.fs=fs;};//fsをコンストラクタから受け取る ファイルの相対パスをmain.jsがあるディレクトリからにするasyncwrite1(content){constfs=this.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-------------------------------\n${e}\n-------------------------------\n`)}};//fsをメソッド内でインポートする ファイルの相対パスをmain.jsがあるディレクトリからにするasyncwrite2(content){constfs=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-------------------------------\n${e}\n-------------------------------\n`)}};//fsをコンストラクタから受け取る ファイルの相対パスをfileManeger.jsがあるディレクトリからにするasyncwrite3(content){constfs=this.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-------------------------------\n${e}\n-------------------------------\n`)}};//fsをメソッド内でインポートする ファイルの相対パスをfileManeger.jsがあるディレクトリからにするasyncwrite4(content){constfs=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-------------------------------\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 |
実行結果
./config/write-〇.json
のパスであるwrite1メソッドとwrite2メソッドは成功している。
一方、../config/write-〇.json
のパスであるwrite3メソッドとwrite4メソッドは読み込めないとエラーが出ている。
結論
以上のことから、fsのファイルパスの起点はnode.jsで実行しているファイルがあるディレクトリであることがわかった。
よって、fsを使用したコードのエラーでError: ENOENT: no such file or directory, openが出た際は、ファイルのパスがnode.jsで実行しているファイルがあるディレクトリからの相対パスになっているか確認しよう。
参考
公式ドキュメントにファイルパスの話が出ているのでその部分のリンクを記載しておく。
Node.js v14.13.1 Documentation
検証に使用したソースコード
github huda0209/qitta_fs-sample