【Node.js】ファイルの入出力処理を行う(同期処理、Promiseによる非同期処理)
Node.jsでファイル操作を行う
Node.jsでファイルの入出力処理を行うには、次の方法があります。
- 同期処理 (←おすすめ)
- コールバックによる非同期処理
- Promiseによる非同期処理 (←おすすめ)
同期処理で良い状況なら、同期処理を使うのがシンプルです。
もし、非同期処理を書く必要があるときには、Promiseによる非同期処理を書くほうが見やすく書けるので、おすすめです。
それぞれの方法でファイル入出力処理を書く
「ファイルを読み込んで、その内容を別のファイルに出力する」プログラムをTypeScriptで書いてみます。
下記環境で、プログラムを実行しています。
- Node.js 12.13.0
- TypeScript 4.0.3
- ts-node 9.0.0
1. 同期処理
import fs from 'fs';
const inputFilepath = './file/input.txt';
const outputFilepath = './file/output_syncronous.txt';
const main = () => {
try {
const data = fs.readFileSync(inputFilepath, 'utf-8');
console.log(data);
fs.writeFileSync(outputFilepath, data);
console.log(`Write to ${outputFilepath}`);
} catch (e) {
//エラー処理
console.log(e);
}
};
main();
fs
モジュールをimportし、fs.readFileSync
でファイル読み込み、fs.writeFileSync
でファイル出力を行います。
すべて、同期的に処理されるので、流れが、とてもわかりやすいです。
なお、ファイル操作に失敗した場合には例外が発生します。そこで、try
~catch
を使って、例外処理を行いましょう。
2. コールバックによる非同期処理
import fs from 'fs';
const inputFilepath = './file/input.txt';
const outputFilepath = './file/output_callback.txt';
const main = () => {
fs.readFile(inputFilepath, 'utf-8', (err, data) => {
if (err) {
//エラー処理
console.log(err);
return;
}
console.log(data);
fs.writeFile(outputFilepath, data, (err) => {
if (err) {
//エラー処理
console.log(err);
return;
}
console.log(`Write to ${outputFilepath}`);
});
});
};
main();
先ほどと同じようにfs
モジュールをimportします。
コールバックによる非同期処理をする場合には、fs.readFile
でファイル読み込み、fs.writeFile
でファイル出力を行います。
これらの関数を使う場合には、3つめの引数に、コールバック関数を渡す必要があります。
たとえば、読み込み処理の場合には、(err, data) => { ... }
の形のコールバック関数を渡します。処理がうまくいった場合には、引数data
に、処理結果が格納されるので、この引数を使って後続処理を書いていくことになります。
逆に、うまくいかなかった場合にはerr
に値が設定されるので、その内容を使ってエラー処理を行ってください。
同様に、出力処理の場合には、(err) => { ... }
の形のコールバック関数を渡して、後続処理を記述していきます。
コールバック関数を使うと、ネストがどんどん深くなるので、とても記述がしにくいです。ですから、この方法を使うことはおすすめしません。
3. Promiseによる非同期処理
import { promises as fs } from 'fs';
const inputFilepath = './file/input.txt';
const outputFilepath = './file/output_promise.txt';
const main = async () => {
try {
const data = await fs.readFile(inputFilepath, 'utf-8');
console.log(data);
await fs.writeFile(outputFilepath, data);
console.log(`Write to ${outputFilepath}`);
} catch (e) {
//エラー処理
console.log(e);
}
};
main();
Promiseによる非同期処理をする場合には、まずimport文の書き方を変える必要があります。import { promises as fs } from 'fs';
というようにしてインポートをしてください。
そして、fs.readFile
でファイル読み込み、fs.writeFile
でファイル出力を行います。
Promiseを使う書き方には何パターンか書き方がありますが、上の例では、async-awaitを使って記述をしています。
まず、ファイル入出力をする関数main
をasync
関数として宣言します。
そして、fs.readFile
、fs.writeFile
の処理時にawait
キーワードを付けて処理を行います。
こうすることで、同期処理と、ほとんど同じ書き方で書くことができます。
もし、async
、await
を使わずに、then
を使って書くのであれば、次のような感じに書くことができます。
import { promises as fs } from 'fs';
const inputFilepath = './file/input.txt';
const outputFilepath = './file/output_promise2.txt';
const main = () => {
fs.readFile(inputFilepath, 'utf-8')
.then((data) => {
console.log(data);
return fs.writeFile(outputFilepath, data);
})
.then(() => {
console.log(`Write to ${outputFilepath}`);
})
.catch((e) => {
//err処理
console.log(e);
});
};
main();
括弧は増えましたが、それでも、コールバックを使う書き方よりは、見やすいでしょう。
githubリポジトリ
今回のプログラムは、下記に上げています。