Node.js
ファイルシステムI / O
サーチ…
備考
Node.jsでは、I / Oなどのリソース集約型操作は非同期に実行されますが、 同期した対応があります(たとえば、 fs.readFile
が存在し、対応するものがfs.readFileSync
)。 Nodeはシングルスレッドなので、 同期操作を使用するときはプロセス全体をブロックするので注意が必要です。
プロセスが同期動作によってブロックされた場合、実行サイクル全体(イベントループを含む)は停止されます。つまり、イベントやイベントハンドラを含む他の非同期コードは実行されず、プログラムは単一のブロック操作が完了するまで待機し続けます。
同期操作と非同期操作の両方に適切な用途がありますが、正しく使用されるように注意する必要があります。
writeFileまたはwriteFileSyncを使用したファイルへの書き込み
var fs = require('fs');
// Save the string "Hello world!" in a file called "hello.txt" in
// the directory "/tmp" using the default encoding (utf8).
// This operation will be completed in background and the callback
// will be called when it is either done or failed.
fs.writeFile('/tmp/hello.txt', 'Hello world!', function(err) {
// If an error occurred, show it and return
if(err) return console.error(err);
// Successfully wrote to the file!
});
// Save binary data to a file called "binary.txt" in the current
// directory. Again, the operation will be completed in background.
var buffer = new Buffer([ 0x48, 0x65, 0x6c, 0x6c, 0x6f ]);
fs.writeFile('binary.txt', buffer, function(err) {
// If an error occurred, show it and return
if(err) return console.error(err);
// Successfully wrote binary contents to the file!
});
fs.writeFileSync
と同様に動作しますfs.writeFile
が、それはメインスレッド同期ので、ブロックを完了すると、コールバックを取ることはありません。ほとんどのnode.js開発者は、プログラムの実行に事実上遅延を生じさせない非同期バリアントを好んでいます。
注:メインスレッドをブロックすることは、node.jsでは悪いことです。同期関数は、デバッグ時または他のオプションが使用できないときにのみ使用する必要があります。
// Write a string to another file and set the file mode to 0755
try {
fs.writeFileSync('sync.txt', 'anni', { mode: 0o755 });
} catch(err) {
// An error occurred
console.error(err);
}
ファイルから非同期に読み取り
すべてのファイル操作にfilesystemモジュールを使用します。
const fs = require('fs');
エンコーディング付き
この例では、ディレクトリ/tmp
からhello.txt
を読み込みます。この操作はバックグラウンドで完了し、完了または失敗時にコールバックが発生します。
fs.readFile('/tmp/hello.txt', { encoding: 'utf8' }, (err, content) => {
// If an error occurred, output it and return
if(err) return console.error(err);
// No error occurred, content is a string
console.log(content);
});
エンコーディングなし
バイナリファイルbinary.txt
を現在のディレクトリから、バックグラウンドで非同期で読み取ります。 'encoding'オプションは設定しないことに注意してください。これにより、Node.jsが内容を文字列にデコードすることができなくなります。
fs.readFile('binary', (err, binaryContent) => {
// If an error occurred, output it and return
if(err) return console.error(err);
// No error occurred, content is a Buffer, output it in
// hexadecimal representation.
console.log(content.toString('hex'));
});
相対パス
一般的な場合、スクリプトは任意の現在の作業ディレクトリで実行できることに注意してください。現在のスクリプトと相対的なファイルを指定するには、 __dirname
または__filename
使用します。
fs.readFile(path.resolve(__dirname, 'someFile'), (err, binaryContent) => {
//Rest of Function
}
readdirまたはreaddirSyncを使用してディレクトリの内容を表示する
const fs = require('fs');
// Read the contents of the directory /usr/local/bin asynchronously.
// The callback will be invoked once the operation has either completed
// or failed.
fs.readdir('/usr/local/bin', (err, files) => {
// On error, show it and return
if(err) return console.error(err);
// files is an array containing the names of all entries
// in the directory, excluding '.' (the directory itself)
// and '..' (the parent directory).
// Display directory entries
console.log(files.join(' '));
});
同期バリアントは、メインスレッドをブロックするreaddirSync
として利用でき、同時に非同期コードの実行を防止します。ほとんどの開発者は、パフォーマンスを向上させるために同期入出力機能を使用しません。
let files;
try {
files = fs.readdirSync('/var/tmp');
} catch(err) {
// An error occurred
console.error(err);
}
ジェネレータの使用
const fs = require('fs');
// Iterate through all items obtained via
// 'yield' statements
// A callback is passed to the generator function because it is required by
// the 'readdir' method
function run(gen) {
var iter = gen((err, data) => {
if (err) { iter.throw(err); }
return iter.next(data);
});
iter.next();
}
const dirPath = '/usr/local/bin';
// Execute the generator function
run(function* (resume) {
// Emit the list of files in the directory from the generator
var contents = yield fs.readdir(dirPath, resume);
console.log(contents);
});
ファイルから同期して読み込む
どのファイル操作でも、filesystemモジュールが必要です:
const fs = require('fs');
文字列を読む
fs.readFileSync
と同様に動作しますfs.readFile
が、それはメインスレッド同期ので、ブロックを完了すると、コールバックを取ることはありません。ほとんどのnode.js開発者は、プログラムの実行に事実上遅延を生じさせない非同期バリアントを好んでいます。
encoding
オプションが指定されている場合は文字列が返され、そうでない場合はBuffer
が返されます。
// Read a string from another file synchronously
let content;
try {
content = fs.readFileSync('sync.txt', { encoding: 'utf8' });
} catch(err) {
// An error occurred
console.error(err);
}
unlinkまたはunlinkSyncを使用してファイルを削除する
非同期でファイルを削除する:
var fs = require('fs');
fs.unlink('/path/to/file.txt', function(err) {
if (err) throw err;
console.log('file deleted');
});
同期的に削除することもできます*:
var fs = require('fs');
fs.unlinkSync('/path/to/file.txt');
console.log('file deleted');
*同期メソッドは、実行が終了するまでプロセス全体をブロックするので避けてください。
ストリームを使用してファイルをバッファに読み込む
fs.readFile()
メソッドを使用すると、ファイルからコンテンツを読み込むことはすでに非同期ですが、単純なコールバックではなく、ストリームでデータを取得したいことがあります。これにより、このデータを他の場所にパイプしたり、終わりに一度にすべてのデータを処理したりすることができます。
const fs = require('fs');
// Store file data chunks in this array
let chunks = [];
// We can use this variable to store the final data
let fileBuffer;
// Read file into stream.Readable
let fileStream = fs.createReadStream('text.txt');
// An error occurred with the stream
fileStream.once('error', (err) => {
// Be sure to handle this properly!
console.error(err);
});
// File is done being read
fileStream.once('end', () => {
// create the final data Buffer from data chunks;
fileBuffer = Buffer.concat(chunks);
// Of course, you can do anything else you need to here, like emit an event!
});
// Data is flushed from fileStream in chunks,
// this callback will be executed for each chunk
fileStream.on('data', (chunk) => {
chunks.push(chunk); // push data chunk to array
// We can perform actions on the partial data we have so far!
});
ファイルまたはディレクトリのアクセス許可を確認する
fs.access()
は、パスが存在するかどうか、およびユーザーがそのパスのファイルまたはディレクトリに対するアクセス許可を判断します。 fs.access
は結果を返しません。エラーを返さない場合、パスは存在し、ユーザーには必要な権限が与えられます。
パーミッションモードは、 fs
オブジェクトのプロパティとして利用できますfs.constants
-
fs.constants.F_OK
- 読み取り/書き込み/実行権限をfs.constants.F_OK
ます(モードが指定されていない場合はこれがデフォルトです) -
fs.constants.R_OK
- 読み込み権限があります -
fs.constants.W_OK
- 書き込み権限を持っています -
fs.constants.X_OK
- 実行権限をfs.constants.F_OK
ます(Windowsではfs.constants.F_OK
と同じようにfs.constants.F_OK
します)
非同期に
var fs = require('fs');
var path = '/path/to/check';
// checks execute permission
fs.access(path, fs.constants.X_OK, (err) => {
if (err) {
console.log("%s doesn't exist", path);
} else {
console.log('can execute %s', path);
}
});
// Check if we have read/write permissions
// When specifying multiple permission modes
// each mode is separated by a pipe : `|`
fs.access(path, fs.constants.R_OK | fs.constants.W_OK, (err) => {
if (err) {
console.log("%s doesn't exist", path);
} else {
console.log('can read/write %s', path);
}
});
同期的に
fs.access
、同期バージョンがあるfs.accessSync
。 fs.accessSync
を使用fs.accessSync
場合は、try / catchブロック内に囲む必要があります。
// Check write permission
try {
fs.accessSync(path, fs.constants.W_OK);
console.log('can write %s', path);
}
catch (err) {
console.log("%s doesn't exist", path);
}
既存のディレクトリを作成または使用する際の競合条件の回避
ノードの非同期性のため、最初にディレクトリを作成または使用する:
-
fs.stat()
でその存在を確認し、次に - 存在チェックの結果に応じて作成または使用するか、
チェックの時間と作成の時間との間にフォルダが作成された場合、 競合状態になる可能性があります。以下のメソッドは、 fs.mkdir()
とfs.mkdirSync()
を、そのコードがEEXIST
(すでに存在する)の場合に例外を受け渡しさせるエラーキャッチラッパーにラップします。エラーがEPERM
(pemission denied)のようなものであれば、ネイティブ関数のようにエラーを投げたり渡したりします。
fs.mkdir()
をfs.mkdir()
非同期バージョン
var fs = require('fs'); function mkdir (dirPath, callback) { fs.mkdir(dirPath, (err) => { callback(err && err.code !== 'EEXIST' ? err : null); }); } mkdir('./existingDir', (err) => { if (err) return console.error(err.code); // Do something with `./existingDir` here });
fs.mkdirSync()
との同期バージョン
function mkdirSync (dirPath) { try { fs.mkdirSync(dirPath); } catch(e) { if ( e.code !== 'EEXIST' ) throw e; } } mkdirSync('./existing-dir'); // Do something with `./existing-dir` now
ファイルまたはディレクトリが存在するかどうかを確認する
非同期に
var fs = require('fs');
fs.stat('path/to/file', function(err) {
if (!err) {
console.log('file or directory exists');
}
else if (err.code === 'ENOENT') {
console.log('file or directory does not exist');
}
});
同期的に
ここでは、エラーを処理するためにtry/catch
ブロックに関数呼び出しをラップする必要があります。
var fs = require('fs');
try {
fs.statSync('path/to/file');
console.log('file or directory exists');
}
catch (err) {
if (err.code === 'ENOENT') {
console.log('file or directory does not exist');
}
}
ストリームを使用したファイルのクローン作成
このプログラムは、ファイルシステムモジュールによって提供されるcreateReadStream()
およびcreateWriteStream()
関数を使用して、読み書き可能なストリームを使用してファイルをコピーする方法を示しています。
//Require the file System module
var fs = require('fs');
/*
Create readable stream to file in current directory (__dirname) named 'node.txt'
Use utf8 encoding
Read the data in 16-kilobyte chunks
*/
var readable = fs.createReadStream(__dirname + '/node.txt', { encoding: 'utf8', highWaterMark: 16 * 1024 });
// create writable stream
var writable = fs.createWriteStream(__dirname + '/nodeCopy.txt');
// Write each chunk of data to the writable stream
readable.on('data', function(chunk) {
writable.write(chunk);
});
パイプストリームによるファイルのコピー
このプログラムは、ストリームクラスによって提供されるpipe()
関数を使用して、読み込み可能なストリームと書き込み可能なストリームを使用してファイルをコピーします。
// require the file system module
var fs = require('fs');
/*
Create readable stream to file in current directory named 'node.txt'
Use utf8 encoding
Read the data in 16-kilobyte chunks
*/
var readable = fs.createReadStream(__dirname + '/node.txt', { encoding: 'utf8', highWaterMark: 16 * 1024 });
// create writable stream
var writable = fs.createWriteStream(__dirname + '/nodePipe.txt');
// use pipe to copy readable to writable
readable.pipe(writable);
テキストファイルの内容を変更する
例。単純なRegExp replace(/email/gim, 'name')
というテキストファイルindex.txt
name
にemail
というname
をreplace(/email/gim, 'name')
var fs = require('fs');
fs.readFile('index.txt', 'utf-8', function(err, data) {
if (err) throw err;
var newValue = data.replace(/email/gim, 'name');
fs.writeFile('index.txt', newValue, 'utf-8', function(err, data) {
if (err) throw err;
console.log('Done!');
})
})
テキストファイルの行数の決定
app.js
const readline = require('readline');
const fs = require('fs');
var file = 'path.to.file';
var linesCount = 0;
var rl = readline.createInterface({
input: fs.createReadStream(file),
output: process.stdout,
terminal: false
});
rl.on('line', function (line) {
linesCount++; // on each linebreak, add +1 to 'linesCount'
});
rl.on('close', function () {
console.log(linesCount); // print the result when the 'close' event is called
});
使用法:
ノードアプリ
行単位でファイルを読み込む
app.js
const readline = require('readline');
const fs = require('fs');
var file = 'path.to.file';
var rl = readline.createInterface({
input: fs.createReadStream(file),
output: process.stdout,
terminal: false
});
rl.on('line', function (line) {
console.log(line) // print the content of the line on each linebreak
});
使用法:
ノードアプリ