ノードには、ネットワーク ストリームと同様にファイルを処理できる一連のデータ ストリーム API があり、非常に便利ですが、ファイルの順次処理のみが可能であり、ファイルをランダムに読み書きすることはできません。したがって、いくつかの下位レベルのファイル システム操作を使用する必要があります。
この章では、ファイルを開く方法、ファイルの一部を読み取る方法、データを書き込む方法、ファイルを閉じる方法など、ファイル処理の基本について説明します。
Node のファイル API の多くは、UNIX (POSIX) の対応するファイル API のほぼレプリカです。たとえば、Node のファイル記述子も、UNIX と同様の整数です。エンティティ。プロセス ファイル記述子テーブルのインデックス。
1、2、3 という 3 つの特殊なファイル記述子があります。これらはそれぞれ、標準入力、標準出力、および標準エラーのファイル記述子を表します。標準入力は、名前が示すように、プロセスがコンソールまたはプロセス チャネルからデータを読み取るために使用する読み取り専用ストリームです。標準出力と標準エラーは、データを出力するためだけに使用されるファイル記述子であり、コンソール、他のプロセス、またはファイルにデータを出力するためによく使用されます。標準エラーはエラー情報の出力を担当し、標準出力は通常のプロセスの出力を担当します。
プロセスが開始されると、これらのファイル記述子は実際には対応する物理ファイルを持ちません。ランダムな位置でデータを読み書きすることはできません (翻訳者注: 原文は、ファイル内の特定の位置に書き込んだり、特定の位置から読み込んだりすることができます。文脈によっては、作成者は「そうではない」と書いている可能性があります)。データはデータストリームのように順次読み取られて出力され、書き込まれたデータを変更することはできません。
通常のファイルにはこの制限はありません。たとえば、Node では末尾にのみデータを追加できるファイルを作成したり、ランダムな場所に読み書きするファイルを作成したりすることもできます。
ほぼすべてのファイル関連の操作にはファイル パスの処理が含まれます。この章では、まずこれらのツールの機能を紹介し、次にファイルの読み取り、書き込み、データ操作について詳しく説明します。
ファイル パスを処理しています
ファイル パスは相対パスと絶対パスに分けられ、特定のファイルを表すために使用されます。ファイル パスを結合したり、ファイル名情報を抽出したり、ファイルが存在するかどうかを検出したりすることもできます。
Node では、文字列を使用してファイル パスを処理できますが、たとえば、パスの異なる部分を接続する場合、「/」で終わる部分とそうでない部分があり、問題が複雑になります。パス区切り文字も異なるため、オペレーティング システムも異なる可能性があるため、それらを接続すると、コードが非常に冗長で煩雑になります。
幸いなことに、Node には path と呼ばれるモジュールがあり、パスの標準化、接続、解析、絶対パスから相対パスへの変換、パスからの情報のさまざまな部分の抽出、ファイルが存在するかどうかの検出に役立ちます。一般に、パス モジュールは実際には単なる文字列処理であり、検証のためにファイル システムに送信されることはありません (path.exists 関数を除く)。
パスの標準化
通常、パスを保存または使用する前にパスを正規化することをお勧めします。たとえば、ユーザー入力または構成ファイルによって取得されたファイル パス、または 2 つ以上のパスで接続されたパスは、通常、標準化する必要があります。 path モジュールの正規化関数を使用すると、パスを正規化できます。また、「..」、「.」、「//」も処理できます。例:
path.normalize('/foo/bar//baz/asdf/quux/..');
// => '/foo/bar/baz/asdf'
接続パス
path.join() 関数を使用すると、すべてのパス文字列を join() 関数に順番に渡すだけで、任意の数のパス文字列を接続できます。
// => '/foo/bar/baz/asdf'
ご覧のとおり、path.join() は内部でパスを自動的に正規化します。
パスを解析します
複数のパスを絶対パスに解決するには、path.resolve() を使用します。その機能は、これらのパスに対して 1 つずつ「cd」操作を実行するのと似ています。cd コマンドのパラメーターとは異なり、これらのパスはファイルにすることができ、実際に存在する必要はありません。path.resolve() メソッドはアクセスしません。パスが存在するかどうかを判断します。これは単なる文字列操作です。
例:
path.resolve('/foo/bar', './baz');
// => /foo/bar/baz
path.resolve('/foo/bar', '/tmp/file/');
// => /tmp/file
解析結果が絶対パスでない場合、path.resolve() は現在の作業ディレクトリをパスとして解析結果の前に追加します。例:
2 つの絶対パスの相対パスを計算します
path.relative() は、次のように、ある絶対アドレスから別の絶対アドレスにジャンプする方法を示します。
// => ../../impl/bbb
パスからデータを抽出します
親ディレクトリ (/foo/bar) のすべての内容を取得する場合、または同じディレクトリ内の他のファイルを読み取る場合は、パス「/foo/bar/myfile.txt」を例に挙げます。 、 path.dirname(filePath) を使用する必要があります。 のように、ファイル パスのディレクトリ部分を取得します。
// => /foo/bar/baz/asdf
ファイル パスにはファイル拡張子も含まれる場合があります。これは通常、ファイル名の最後の「.」文字の後の文字列の部分です。
path.basename は 2 番目のパラメータとして拡張子文字列を受け入れることもできるため、返されるファイル名は自動的に拡張子を削除し、ファイルの名前部分のみを返します。
path.basename('/foo/bar/baz/asdf/quux.html', '.html');
// => '.html'
path.extname('/a/b.c/index');
// =>
path.extname('/a/b.c/.');
// =>
path.extname('/a/b.c/d.');// =>
パスが存在するかどうかを確認します
これまでのところ、上記のパス処理操作は基礎となるファイル システムとは何の関係もなく、単なる文字列操作です。ただし、ファイル パスが存在するかどうかを判断する必要がある場合があります。たとえば、ファイルまたはディレクトリが存在するかどうかを判断し、存在しない場合は path.exsits(): を使用できます。
コードをコピー
// = & gt;
});
path.exists('/does_not_exist', function(exists) {
console.log('exists:', 存在します);
});
注: Node 0.8 バージョン以降、exists は path モジュールから fs モジュールに移動され、fs.exists に変更されました。名前空間以外は何も変更されていません。
fs.exists('/does_not_exist', function(exists) {
console.log('exists:', 存在します);
});
// => true
fs モジュールの紹介
fs モジュールには、ファイルのクエリと処理に関連するすべての関数が含まれており、これらの関数を使用して、ファイル情報のクエリ、ファイルの読み取り、書き込み、および閉じることができます。次のように fs モジュールをインポートします:
ファイル情報のクエリ
ファイル サイズ、作成日、権限、その他のファイル情報が必要になる場合があります。fs.stath 関数を使用して、ファイルまたはディレクトリのメタ情報をクエリできます。
if (err) { throw err;}
console.log(統計);
});
モード: 33188、
nlink: 1,
uid: 0、
gid: 0,
rdev: 0、
サイズ: 5086、
BLKサイズ: 4096、
ブロック: 0、
時刻: 2011 年 11 月 18 日金曜日 22:44:47 GMT、
時刻: 2011 年 9 月 8 日木曜日 23:50:04 GMT、
ctime: 木、08 Sep 2011 23:50:04 GMT }
1. fs.stat() 呼び出しは、stats クラスのインスタンスをパラメーターとしてコールバック関数に渡します。
stats インスタンスは次のように使用できます。2.stats.isFile() - ディレクトリ、ソケット、シンボリック リンク、またはデバイスではなく、標準ファイルの場合は true を返し、それ以外の場合は false
3.stats.isDiretory() - ディレクトリの場合は true を返し、それ以外の場合は false
を返します。
4.stats.isBlockDevice() - ブロック デバイスの場合、true を返します。ほとんどの UNIX システムでは、ブロック デバイスは通常、/dev ディレクトリ
にあります。
5.stats.isCharcterDevice() - キャラクターデバイス
の場合はtrueを返します。
6.stats.isSymbolickLink() - ファイルリンクの場合は true を返します
7.stats.isFifo() - FIFO (特別なタイプの UNIX 名前付きパイプ) の場合は true を返します
8.stats.isSocket() - UNIX ソケットの場合 (TODO: ググってください)
ファイルを開く
ファイルを読み取ったり処理したりする前に、まず fs.open 関数を使用してファイルを開く必要があります。その後、指定したコールバック関数が呼び出され、ファイル記述子を取得して、後で読み取ることができます。このすでに開いているファイル:
fs.open('/path/to/file', 'r', function(err, fd) {
// fd ファイル記述子を取得しました
});
fs.open の最初のパラメータはファイル パスで、2 番目のパラメータはファイルを開くモードを示すために使用されるタグです。これらのタグは、r、r、w、w、a、または a です。以下はこれらのタグの説明です (UNIX ドキュメントの fopen ページから)
1.r - ファイルを読み取り専用モードで開きます。データ ストリームの初期位置はファイルの先頭です
2.r - ファイルを読み取り/書き込みモードで開きます。データ ストリームの初期位置はファイルの先頭です
3.w - ファイルが存在する場合、ファイルの長さは 0 にクリアされます。つまり、ファイルの内容は失われます。存在しない場合は、作成してみてください。データ ストリームの初期位置はファイルの先頭です
4.w - ファイルを読み取り/書き込みモードで開きます。ファイルが存在しない場合は、ファイルの長さを 0 に設定します。つまり、ファイルの内容は失われます。データ ストリームの初期位置はファイルの先頭です
5.a - ファイルを書き込み専用モードで開きます。ファイルが存在しない場合は、データ ストリームの最初の位置がファイルの最後に追加されます。ファイルの終わり。
6.a - 読み取りおよび書き込みのためにファイルを開きます。ファイルが存在しない場合は、データ ストリームの最初の位置がファイルの最後に追加されます。ファイルの。
ファイルの読み取り
ファイルを開いたら、ファイルの内容の読み取りを開始できますが、開始する前に、まずデータを配置するためのバッファーを作成する必要があります。このバッファ オブジェクトはパラメータとして fs.read 関数に渡され、fs.read によってデータが埋められます。
fs.open('./my_file.txt', 'r', 関数が開かれました (err, fd) {
if (err) { throw err }
var readBuffer = new Buffer(1024),
バッファオフセット = 0,
bufferLength = readBuffer.length,
filePosition = 100;
fs.read(fd,
readBuffer、
バッファオフセット、
バッファ長、
ファイル位置、
function read(err, readBytes) {
if (err) { throw err; }
console.log('just read ' readBytes ' bytes');
if (readBytes > 0) {
console.log(readBuffer.slice(0, readBytes));
}
});
});
上のコードはファイルを開き、正常に開くと (開かれた関数を調整)、ファイル ストリームの 100 文字から次の 1024 文字のデータの取得を要求し始めます (11 行目)。
fs.read() の最後のパラメータは回帰関数 (第 16 行) であり、当下三件発生時、它会被调用:1.有错误発行
2.成功读取了データ
3.データなしで读
圧縮エリアデータの大きさを調べ、値が 0 の場合、ファイルの末尾が表示されることを示します。
注意: 缓冲区オブジェクトの制御が完了すると、コマンドが読み取られ、缓冲区オブジェクトの制御权が转移给了されます。したがって、これに先立って、この圧縮領域オブジェクトを使用して他の関数を調整したり、不完全なデータを送信したりする可能性があり、さらにその場合、この圧縮領域オブジェクトを送信して送信される可能性があります。データを書き込みます。
写文
通传递给fs.write() 传递一包含データ的缓冲对,来往一已打开的文件里写数据:
if (err) { throw err; }
var writeBuffer = new Buffer('この文字列の書き込み'),
bufferPosition = 0,
bufferLength = writeBuffer.length、filePosition = null;
fs.write( fd,
writeBuffer,
バッファ位置、
バッファ長、
ファイル位置、
関数が書きました(err、書かれました) {
if (err) { throw err; }
console.log('書き込んだ ' バイト');
});
});
この例では、コードの 2 行目 (翻訳者注: 原文は 3) が追加モード (a) でファイルを開こうとし、次にコードの 7 行目 (翻訳者注: 原文は 9) が次のように書き込みます。データをファイルにコピーします。バッファ オブジェクトには、パラメータとしていくつかの情報を伴う必要があります:
1. バッファーデータ
2. 書き込まれるデータはバッファ内のどこから始まりますか
3. 書き込むデータの長さ
4.データはファイル内のどの場所に書き込まれますか?
5. 操作の完了時に呼び出されるコールバック関数 write
この例では、filePostion パラメーターは null です。これは、書き込み関数がファイル ポインターの現在の場所にデータを書き込むことを意味します。ファイルは追加モードで開かれるため、ファイル ポインターはファイルの最後にあります。ファイル。
読み取り操作と同様に、fs.write の実行中に受信バッファ オブジェクトを使用しないでください。fs.write が実行を開始すると、そのバッファ オブジェクトの制御が取得されます。コールバック関数を再度使用するには、コールバック関数が呼び出されるまで待つ必要があります。
ファイルを閉じる
お気づきかもしれませんが、この章のこれまでの例にはファイルを閉じるコードがありません。これらは 1 回だけ使用される小規模で単純な例であるため、ノード プロセスの終了時にオペレーティング システムによってすべてのファイルが閉じられるようになります。
しかし、実際のアプリケーションでは、ファイルを開いたら、最終的には必ず閉じる必要があります。これを行うには、開いているファイル記述子をすべて追跡し、使用されなくなったら fs.close(fd[,callback]) を呼び出して最終的に閉じる必要があります。注意しないとファイル記述子を見逃してしまいがちです。次の例は、openAndWriteToSystemLog という関数を提供し、ファイルを慎重に閉じる方法を示しています。
ここでは、書き込むデータを含むバッファ オブジェクトを受け取る openAndWriteToSystemLog という関数と、操作の完了後またはエラーが発生した場合に呼び出されるコールバック関数が提供されています。パラメータにはエラー オブジェクトが含まれます。
内部関数notifyErrorに注目してください。この関数はファイルを閉じて、発生したエラーを報告します。
注: この時点で、低レベルのアトミック操作を使用してファイルを開いたり、読み取り、書き込み、閉じたりする方法がわかりました。ただし、Node には、より簡単な方法でファイルを操作できるようにする、より高度なコンストラクターのセットもあります。
たとえば、安全な方法を使用して、2 つ以上の書き込み操作でファイルにデータを同時に追加できるようにしたい場合は、WriteStream を使用できます。
また、ファイルの特定の領域を読み取りたい場合は、ReadStream の使用を検討してください。これら 2 つの使用例は、第 9 章「データの読み取りおよび書き込みストリーム」で紹介されます。
概要
ファイルを使用する場合、ほとんどの場合、ファイル パス情報を処理して抽出する必要があります。パス モジュールを使用すると、パスの連結、パスの標準化、パスの差分の計算、および相対パスから絶対パスへの変換を行うことができます。指定したファイル パスの拡張子、ファイル名、ディレクトリ、およびその他のパス コンポーネントを抽出できます。
ノードは、ファイル システムにアクセスするための一連の低レベル API を fs モジュールに提供します。低レベル API はファイル記述子を使用してファイルを操作します。 fs.open でファイルを開き、fs.write でファイルに書き込み、fs.read でファイルを読み取り、fs.close でファイルを閉じることができます。
エラーが発生した場合は、常に適切なエラー処理ロジックを使用してファイルを閉じる必要があります。呼び出しが返される前に、開いているファイル記述子が確実に閉じられるようにしてください。