【プログラミング入門の入門】fsモジュールでファイルの入出力を覚えよう

javascript

プログラミング Node.js fs

こんにちは。継続の錬金術士なおキーヌです。

ブログ毎日更新は206日目になります。

第4回目はNode.jsを導入しました。

Node.jsをつかえるようになるとプログラミングの幅が一気に広がります。

というのも、プレーンなJavaScriptだけだと組むのが大変な機能をモジュールという単位に一つにまとめて、
私たちはそれを呼び出すだけで便利な機能を使うことが出来るようになるのです。

ファイルの読み書き一つもプレーンなJavaScriptでは結構大変なので
今回は「fs」というNode.jsに元々入っているモジュールを利用してファイルの読み書きをしてみます。

それではプログラミングの入門の入門第5回目始めましょう。

  1. Node.jsを使う環境を作ってみよう
  2. テキストファイルを読み込んでみよう
  3. 新たなテキストファイルを出力しよう

Node.jsを使う環境を作ってみよう

それじゃあ早速Node.jsを使ってプロジェクトを作っていくよ

おう!プロジェクトってどうやってつくるんだ?

まずは前回の通り、黒い画面で基本進めていくよ。
コマンドプロンプトを起動したらまずは「mkdir testproject」と打ち込んでみて

よし、「mkdir testproject」だな!……これは何のコマンドなんだ?

mkdirっていうのはフォルダを作る命令だよ。そして、半角空白をはさんで次にある「testproject」っていうフォルダを作れって命令なんだ。
コマンドプロンプトを起動したら特に何も設定していなければ自分のドキュメントフォルダが設定されているはずだから、
ウィンドウズ側でなんかフォルダを開いてドキュメントを見てみてよ。

お、さっき打ち込んだ「testproject」ってフォルダが出来ている!フォルダで右クリックして新規作成しなくてもフォルダって作れるのか!

ウィンドウズをやっている人はフォルダって名前の方が馴染みはあるよね。プログラミングに慣れてくるとフォルダのことをディレクトリって言うようになってくるよ。
さっき打ち込んだ「mkdir」は「メイク ディレクトリ」つまりディレクトリを作れって意味なんだ。

フォルダとそのディレクトリって何が違うんだ?

ボクもそこまで詳しく調べたわけじゃないけど、ウィンドウズやMacのようなグラフィカルな画面ではフォルダって言って、黒い画面ではディレクトリって言うみたいだよ。詳しく知りたいならググってみるといいよ。意外なことも学べるかもしれないね。

わかった、あとで調べておくよ。

話を戻すよ。黒い画面の方に移って次は「cd testproject」って打ち込んでエンターを押してみて

……お、なんか変わったぞ

「cd」ってのはCompactDiscの略ではなくChangeDirectoryの略で現在見ているディレクトリをチェンジするってことなんだ。
Windowsの画面で言うと、ドキュメントのフォルダを開いている状態から「testproject」ってフォルダをダブルクリックした後の状態だね。

なるほどな。でもそれならWindows側で操作したほうがよくないか?

今はまだそう感じるかもしれないけど、慣れてくるといちいちマウスをもって操作するのが面倒くさくなってくるよ。
それにNode.jsは黒い画面じゃないと動かせないでしょ?結局黒い画面で操作するなら全部こっちでやってしまえばいいって感じだね。

今はトモカズに教えてもらってるからいいけど、一人でやるときはコマンド覚えるのが大変だな……

フォルダを作るのはリキくんが言ったようにWindows側で作っても問題ないから、今は黒い画面で「cd ディレクトリパスを指定」することだけ覚えてくれたらいいかな。

わかったぜ!次はどうするんだ?

今はtestprojectのディレクトリの中に居る状態だから、そこで「npm init」って打ち込んでみて

お、なんか出てきたぞ。

「npm init」はNode.jsの初期設定をするコマンドなんだけど、質問形式で入力していくんだ。
最初はとにかくエンターキーを連打して元の画面に戻るところまでやってみて。

戻ったぜ

これでNode.jsを使う準備が出来たよ。

え?

「dir」ってコマンドを打ち込んでみてよ。

なんか一覧みたいなのが表示されたぞ

「dir」はディレクトリの中身を表示するコマンドなんだ。「package.json」ってファイルがあるかな?

あぁ、その名前のファイルはあるぜ

よし、完璧だね。それじゃあ黒い画面は一旦置いといてWindowsの画面に戻ってくれるかな?そしてtestprojectのフォルダの中で「index.js」ってJavaScriptのファイルを作ってくれるかな。

index.js、っと作ったぞ。

その中にコードを書いていくよ。

え?HTMLは書かなくていいのか?

前回も言った通り、ブラウザじゃなくてnode.jsがjavascriptエンジンになっているから必要ないんだよ。

へぇ~!便利だな!

HTMLを気にせずJavaScriptのみでプログラミングできる環境になったから、JavaScriptに集中できるようになるって点でもNode.jsはJavaScriptを勉強したい人にはもってこいの環境なんだ。

テキストファイルを読み込んでみよう

しかし、JavaScriptのファイルに何を書いていけばいいな?いつも通りconsole.logとか書いてもあんまり面白くねぇよ。

console.logは黒い画面にログとして出してくれるから変数や配列の中身を見たいときに使えばいいよ。それじゃあ次のコードを打ちこんでみて。

var fs = require('fs');
console.log(fs);

fsって変数に……りく……なんだこれ?

requireはモジュールを読み込むための関数だよ。中に文字列を書くとその名前のモジュールを読み込めるんだ。
「fs」っていうのはNode.jsに組み込まれているモジュールの1つで名前だけ書けば呼び出せるんだ。

モジュールってなんだ?

例えるなら便利な機能が1つにまとまったファイルだと思ってくれればいいよ。ちなみに自分で作って読み込むことも出来るんだ。
その時は名前の指定だけではなくてそのファイルがある場所も含めて記述しなきゃいけないけど、今は気にしなくていいよ。

あ、あぁ……わけわかんねぇからとりあえずrequire()の中に「”fs”」を打ち込んだぜ。その後のconsole.logで変数の中身も表示するようにした!

それじゃあ黒い画面に戻って「node index.js」って打ち込んでみて

と、トモカズ……なんかわけのわからない英語がたくさん流れてきた!こえぇえよ!

安心して、fsの中身が表示されただけなんだ。よく見てみてよ。「Read」とか「Write」とか書かれているでしょ?

た、たしかに。

安心して、fsの中身が表示されただけなんだ。よく見てみてよ。「Read」とか「Write」とか書かれているでしょ?
「fs」っていうのは「FileSystem」の略でJavaScriptでファイルを扱う機能をまとめたモジュールなんだ。

そういえば普通のJavaScriptはファイルを扱うのがそんなに得意じゃないって言ってたな。これを使えば簡単になるのか?

うん、正直ボクも何も見るなって言われたらこれを使わないとJavaScriptでファイルの読み書きとか出来る自信はないかな。それぐらい便利な機能を持ったモジュールなんだよ。

俺には何年かかっても無理そうだな……しかし「fs」を使えば俺でも簡単に使えるのか?

もちろん!それじゃあ早速Windowsの画面に戻ってテキストファイルを作ってみて。ファイルの名前は「test.txt」って感じでいいよ。気を付けてほしいのは日本語や全角文字を使わないこと。使ってもいいけど文字化けの原因になるし、プログラミングの世界では基本的にファイル名は半角英数以外使わないようにしようね。

わかったぜ!「test.txt」、作ったぜ!

空のファイルだとよくわからないから「test.txt」の中身は以下のように記述して保存しておいて。

12345
67890
abcde
fghij

作ったテキストファイル「test.txt」は「index.js」と同じところに置いててね。それじゃあ早速ファイル読み込みをやっていくよ。「index.js」を以下のように書き換えてね。

// fsという変数にfsモジュールを読み込む
var fs = require('fs');

// fsモジュールを持つfs変数のメソッド「readFile」を使ってファイルを読む
fs.readFile('test.txt', 'utf8', function(error, data) {
  // 中身を出力する
  console.log(data);
});

readFile……ファイルを読むってことか?新しい呪文か!?

fsモジュールが持つreadFileはその名の通りファイルを読み込んでくれるんだ。
カッコの中は引数といって、指定されたものをカンマ区切りで渡してあげないといけないんだ。

パっとみて最初の「text.txt」は作ったファイルだよな?そのあとの「utf8」とfunction~ってのは何だ?

「utf8」は文字コードって言われているもので、ファイルの使用言語だと思っていいよ。
ここでいう言語は、プログラミングって意味ではなくてそのままでボク達日本人だと日本語でアメリカ人だったら英語とかの意味だね。

なるほど……これをやる意味とは?

リキくんは英語はできる?

しゃべるのは無理だけど中学レベルで読むぐらいなら少しは……

わからないところは表しようがないよね。でもプログラムは命令されたことを絶対に動かしてくれるから無理矢理にでも表示しようとするんだ。

じゃあ無茶苦茶な表示をするってことか?

そうだね。いわゆる文字化けってやつだよ。MacとWindowsでメールしたと仮定して、それぞれのOSは文字コードが違うからメールソフトによってはどっちかが文字化けすることがあるんだ。

ってことは「test.txt」は使えるのが「utf8」って文字コードだからここで「utf8」を指定してるのか

保存するエディタによってデフォルト文字コードが違ったりするから、もしかするとリキ君の使っているエディタは「shift-jis」とかshift-jisを拡張した「CP932」って文字コードかもしれないんだ。でも基本的に半角英数であれば文字コードが違っても文字化けはしにくいと思うから一旦は無視してていいよ。文字化けしたときにまた話そうか。

そ、そうだな……今の俺にはちょっと難易度が高いわ……

プログラミングをやっているとこういうわからないけど指定したら動くってのが多々あるから、
深く悩まずに今はこうしたら動くんだってやるのがプログラミング上達のコツだよ。
文系の人をディスるわけじゃないけど、文系の人が数学苦手なのは「なぜこうなるんだ!判るようになるまで先に進まないぞ!」って考えてしまうからダメってのはよく言われているね。

まさに学生時代の俺だ……むしろ今もそんな感じだったな。

数学の公式と同じで、指定されたところに適当なことを当てはめればいいだけなんだ。

プログラミングをしていれば数学も得意になるのか?

うーん、一概には言えないけど数学の見方が学生時代とは変わって楽しくなるかもしれないね。
ボクは少なくともそうなった内の一人なんだ。

なるほどな……で話は戻るけどよ、次の「function」ってのはなんだ?

プログラミングにおいて「function」は関数だって思ってくれればいいよ。
言語によって書き方は違うんだけど今はJavaScriptの場合は「function」って書くと関数だって覚えておけば大丈夫。

関数がまだよくわかってないんだよな……

このfsで使っているreadFileも関数の1つだよ。処理をまとめておいて1つのコードを書くだけで複雑な処理をしたりすることによく使うかな。
readFileの中で使っているfunctionは「コールバック関数」といってreadFileの処理が終わってから動く関数なんだ。

コールバック関数?

もしfunctionの中に何も書かなければreadFileはファイルを読み込むだけで何もしないんだ。
だから、読み込み終わった後に中身を表示してほしいからコールバック関数にconsole.logを書いてあげるんだよ。

ま、まだよくわからんが……とにかくreadFileの処理が終わったら書いた関数が動くってことだな?

うん、それでいいよ。ここではfunctionって書いて処理を書いているけど、別に呼び出す関数はなんでもいいんだ。
別のところで書いた使いまわせる関数名を指定しても良いし、ここでしか使わないならfunctionを使って即時関数を作るのもありだね。

ト、トモカズよ……もうちょっと優しく言ってくれ……脳みそがついていけねぇ……

あぁ、ごめんよリキくん。ちょっとヒートアップしてわかりづらい説明になっちゃったね。
とにかく今はreadFileって関数を呼び出すときには「ファイル名」「文字コード」「処理が終わった後に呼び出したい関数」を指定すれば動くって思ってくれればいいよ。

わかった。で、これを動かしてみたんだけどよ、中身がそのまま表示されたぜ。

12345
67890
abcde
fghij

ファイルを読み込むことに成功しているね。そして読み込んだ後に中身を表示するっていうコールバック関数もちゃんと動いている。完璧だよ!

あとはこれを今まで覚えたことで処理できるのか?

実はこのままだと使い勝手がすごく悪いから、別の方法で読み込まなきゃだめなんだ。

なっ!なぜこんな回りくどいことを!先にそっち教えてくれよ!

まぁまぁ、別の方法と言ってもほとんどやり方は同じだから無駄にはならないよ。
その方法は次回教えてあげるから今は先に進もうね。

なんかうまくしてやられてるような感じがするが……次はファイルを出力するんだったか?

補足しておきますと、readFileはファイルを一気に読み込むので
文字列の中に改行コードが含まれていたり処理するにはちょっと面倒くさい状態になっています。

次回、1行ずつファイルを読み込んで処理できるようにするので一旦ファイルの読み込みはここで終わります。

新たなテキストファイルを出力しよう

そうだね。配列を1行ずつ書き込むのはちょっと説明が難しいから、
一旦変数の中に入っているテキストを別のファイルに書き出すことを覚えようか。

よし、やってやるぜ!

ファイルを書きだす命令は次のようになるよ。

// fsという変数にfsモジュールを読み込む
var fs = require('fs');

var tx = "Node.jsによるファイル書き出しテストだよ";

// fsモジュールを持つfs変数のメソッド「readFile」を使ってファイルを読む
fs.writeFile('writetest.txt', tx, function(error) {
  // エラーがあれば出力する
  console.log(error);
});

なんだ?ほとんど同じだな。違うところは文字コードがない?

そうだね。指定もできるはずだけどない場合はデフォルト文字コードになると思うよ。
やっていることは単純で、「tx」っていう変数の中に入っているものを「writetest.txt」の中に記述して新規ファイルとして書き出すんだ。
コールバック関数はあってもなくてもいいよ。とりあえずエラーが出たら何か表示されるようにしているだけだからあまり気にしないで。

お、実行したら「writetest.txt」ってファイルができたぞ。黒い画面には「null」って表示されてるがこれはなんだ?

エラーがあればnullではなくてエラーコードが表示されるんだけど、nullがそこに出たってことは特にエラーはないってことなんだ。

そういえばポケモンサン&ムーンに「タイプ:ヌル」ってポケモンが居たがあれとなんか関係あるのか?

あのポケモンは人工で造られたって設定らしいからそうだろうね。ヌルは「何もない」ってことなんだ。
0とnullは別物だから気を付けてね。0は0っていう現実があるけどnullは本当に何もないって意味だから。

何もない、か……まるで俺みたいだな!

そ、そんなことないよ。ボクにないものも色々持ってるしこれからプログラミングも覚えるんだからそんな自虐しないでよ……

……トモカズ、ここはツッ込むところだぞ。

あっ、ゴ、ゴメン!

それにしてもすぐ話が横に反れるな俺たち……で、これで一通り終わったってことか?

そうだね。今回はまとめて読み書きしたけどリキ君のやりたいことは1行ずつ処理するものを覚えたほうがいいんだ。

1行ずつってことは処理を繰り返すんだよな?ってことはforを使うのか?

良い発想だね。でも基本的なことはモジュールが全部やってくれるからボクたちは繰り返し処理してほしい「モノ」を渡せばいいだけなんだ。
もし処理結果が気に入らない場合は自力で実装することもできるよ。

Node.jsって便利なんだな。ますます興味がわいてきたぜ!

とりあえず本来の目的を達成してから次を目指そうね。1つ作り上げることができればそれはもうリキ君の能力になっていくんだ。

なんかプログラミングってRPGみたいだな!少しずつ成長してる感じがするぜ!

あ、その発想良いね。じゃあボクはMMORPGでリキ君のレベルアップを手伝ってるイメージかな

見てろよ!今にトモカズを越えるプログラマになってやるからな!

がんばって!(なんか本来の目的を忘れてるような気がするけど、リキ君が成長してくれるなら別になんでも良いか)

簡単なまとめ

今回はNode.jsでfsモジュールを使ってファイルの読み書きを行いました。

リキ君がやるべきことは1行ずつ取り出してその1行をチェックして条件に該当すれば抜き出す。

という処理をしたいので今回のようにまとめて全部読み込む方式では少し面倒くさいです。

次回は応用編として1行ずつ取り出す命令を覚えましょう。

それでは。