Nodejsは、Pythonにも負けずと劣らずライブラリの宝庫になっていて、やりたい事を検索すれば大概のライブラリがnpmコマンドでインストールできるようになっています。
今回やりたい事も、既にライブラリとして存在していますが、僕のサービス構築の基本方針として、なるべくなら余分なモジュールをインストールせずに、サーバーインストール手順を簡易化し、インストールによるミスを軽減する事を重要視しているので、自分でできる事は、ライブラリに頼らないという事を重要視しています。
また、今回Docker+Nodejsという環境で開発作業を行っていた時に問題が発生したので、それなら自分の手で行ってしまえ!という意図で記事にしました。
やりたいこと
サーバーサイドで実行できるJSプログラムということでのNodeJS環境ですが、WEBサイトクローリングや、先日公開したポーリングサービスなどを簡単に実現でき、
ブラウザベースのJSのだと実現できない、データのサーバー書き込みなど、非常に優れた環境がNodeJSで実現できるので、今回は、データ保存をする時に、多重階層になっていた場合、mkdirを一括で行う関数を作りたくて、その奮闘記を書いておきます。
ちなみに、コマンドラインで今回の操作を行うのは、非常に簡単で
$ mkdir -h aaa/bbb/ccc/
とすると、3階層のディレクトリが一発で作成できてしまいます。
同じ要領で、PHPもtrueオプションを付ければ非常に簡単に行なえます。
mkdir("aaa/bbb/ccc/" , true);
nodejsのfsコマンドはファイルとディレクトリ操作を行ってくれるのですが、こうした細部の機能に手が届いていません。
でも、このぐらいであれば、自分でやってしまいましょう。
ライブラリ使えば可能
「fs-extra」という拡張ライブラリがあるらしいのですが、これには、多重階層の一括作成機能などもついているそうです。
一瞬、npmでこのライブラリを入れてしまえば簡単に解決・・・と考えたんですが、npmインストールを行うと独自環境のため、
Maximum call stack size exceeded
というエラーが出て、解決できなくてどうしようも無くなり、これが本番環境で発生したら、非常に困難な状態になることを想定すると、やはり改めてこのぐらいの処理は手書きしてしまったほうがいいと気持ちを改めました。
ソースコード
実際に、構築した関数は以下のとおりです。
function fs_mkdir(path){
if(!path){return;}
var sp = path.split("/");
var p = "";
for(var i=0; i<sp.length; i++){
if(!sp[i]){continue;}
p += sp[i] + "/";
if(isExistPath(p) === false){
console.log("+ "+ p);
fs.mkdirSync(p);
}
}
}
function isExistPath(path) {
try{
fs.accessSync(path);
return true;
}
catch(err){
if(err.code === 'ENOENT') return false;
}
}
解説
今回は関数を2つ作って対応です。
1つ目の関数は、多重階層を分解して上位からフォルダが存在しなければ作っていく関数で、
2つ目の関数で、フォルダの存在確認を行っています。
nodejsでファイルやフォルダの存在確認は「accessSync」か「statSync」を使って行うというのがドキュメントに書かれていたのですが、
普通にif分で使っていると、存在しないフォルダに対して実行すると、プログラムが落ちて終了してしまいました。
どうやら、try-catchでcode判別をしなければイケなかったので、どうしても関数2個という事になってしまいました。
もう少し効率的なコードができるかもしれませんが、とりあえず、こんな簡単なプログラムで実現できてしまったので、これでヨシとしましょう。
最後に
NodeJSを使ったこうしたプログラムを書いて、WEBクロールや、ポーリングシステムと繋げると、今までやっていた作業が簡単に自動化できる事が増えるので、ツール作成をやっていて非常に楽しい限りです。
ちなみに、今回は、WEBクロールしたデータを元に任意階層にデータ保存する時のプログラムでした。
追記
「accessSync」を使うと、うまく返り値が取れないことがわかりました。
下記のように修正して使ってください。
17: fs.accessSync(path);
↓
17: fs.statSync(path);
0 件のコメント:
コメントを投稿