Node.jsでファイルの読み込みreadFileとreadFileSync

[![](https://www.tech-tech.xyz/wp-content/uploads/2018/10/read-text.jpg)](https://www.tech-tech.xyz/wp-content/uploads/2018/10/read-text.jpg)

まよったらreadFileSyncを使う
--------------------

Node.jsをはじめたばかりで「同期?非同期?」な人は、 とりあえず、**fs.readFileSync**を使うのが無難です。 readFileSyncを使うことでJavaやPython,Rubyなど 一般的な言語のファイル読み込みと同じ挙動になります。 下記はファイルを読み込んで、その内容を表示するスクリプトです。

```javascript
const fs = require('fs');
const msg = fs.readFileSync("hoge.txt", {encoding: "utf-8"});
console.log(msg);

実行すると、ファイルの中身が表示されます。

ほげほげふがふが

Node.js風の書き方readFile

次に非同期処理を生かしたNode.js風の書き方をしてみます。 readFileSyncではなく、fs.readFileを利用してみます。

const fs = require('fs');

let msg = '';
fs.readFile('hoge.txt', 'utf-8', (err, data) => {
  // 例外処理
  if (err) { throw err; }

  msg = data;
  console.log(msg);
});

console.log('ファイル読み込み中でも処理が走ります。');

上記のスクリプトを実行すると、環境にもよりますが、 多くの場合、下記のような結果が表示されます。

ファイル実行中でも処理が走ります。
ほげほげふがふが

console.log('ファイル読み込み中でも処理が走ります。') のところが、先に実行されているのがポイントです。 これは、時間のかかるファイルの読み込みの終了を待たずに 次の処理が実行されるよう非同期にコードを書いたからです。 こちらは、Node.jsの強みを生かしたよりNode.jsらしい書き方です。

ブロッキングI/OとノンブロッキングI/O

上記の結果をもう少し掘り下げると、 ノンブロッキングI/OとブロッキングI/Oというとらえ方ができます。

  • fs.readFileSync (ブロッキングI/O)
  • fs.readFile (ノンブロッキングI/O)

つまり、 ブロッキングI/Oはファイルの読み込みが完了するまで待ってから、次の処理を実行します。 ノンブロッキングI/Oは読み込みが完了するのを待たず、次の処理を実行します。

readFileSync,readFileのメリットとデメリット

両者のメリットデメリットをまとめと次のようになります。

readFileSync

  • メリット: 理解しやすく、コードもわかりやすい
  • デメリット: Node.jsのノンブロッキングI/Oの恩恵を得られない

readFile

  • メリット: ノンブロッキングI/Oによるパフォーマンスの向上
  • デメリット: コードが複雑になって、デバッグしづらい

readFileをpromisify(コールバック関数地獄を軽減)

fs.readFileのサンプルコードは コールバック関数で読み込み完了後の処理を書きました。 しかし、読み込み後の処理が複雑になると、 コールバック関数の中にコールバック関数、さらにコールバック関数と… なりコードがとても読みにくくなってしまいます。(通称:コールバック関数地獄) これを解決する方法として、Promiseというデザインパターンを利用する方法があります。 そして、node8から、Promiseを簡単に実装できる promisifyという便利ツールが実装されました。 これを使ってfs.readFileのサンプルコードを書き直すと次のようになります。

const fs = require('fs');
const util = require('util');

const readFile = util.promisfy(fs.readFile);
let msg = '';

readFile('hoge.txt', 'utf-8')
  .then((data) => {
    // thenの中に完了後の処理を書く
    msg = data;
    console.log(msg);
  })
  .catch((err) => {
    // catchの中に例外処理を書く
    throw err;
  });

console.log('ファイル読み込み中でも処理が走ります。');

promise.then(正常処理)promise.catch(例外処理)のような書き方をすることで、 コールバック関数地獄が軽減されます。 とはいえ、今回のような簡単な処理の場合は、 promiseを使った処理は大げさなので、 使いどころを考えるのが重要です。
“`

コメント

タイトルとURLをコピーしました