1. 組み込みモジュールのパス
1.1. パスモジュールについて理解する
path モジュールはパスとファイルの処理に使用され、多くの便利なメソッドを提供します。
そして、Mac OS、Linux、Windows ではパスが異なることもわかっています。
-
ウィンドウは ファイル パスの区切り文字として
\
または を使用します\\
。もちろん、これも現在サポートされています/
。 -
Mac OS、Linux、Unix オペレーティング システムで
/
ファイル パスの区切り文字として使用されます。
では、ウィンドウをセパレータとして使用してウィンドウ上で \
アプリケーションを開発し、それを Linux にデプロイする場合はどうすればよいでしょうか?
-
表示パスにいくつかの問題が発生する可能性があります。
-
したがって、それらの間の違いを保護するために、開発中にパス操作にモジュールを使用できます
path
。
1.2. パスの共通API
パスから情報を取得する
-
dirname: ファイルの親フォルダーを取得します。
-
Basename: ファイル名を取得します。
-
extname: ファイル拡張子を取得します。
const path = require("path");
const myPath = '/Users/coderwhy/Desktop/Node/课堂/PPT/01_邂逅Node.pdf';
const dirname = path.dirname(myPath);
const basename = path.basename(myPath);
const extname = path.extname(myPath);
console.log(dirname); // /Users/coderwhy/Desktop/Node/课堂/PPT
console.log(basename); // 01_邂逅Node.pdf
console.log(extname); // .pdf
パスの継ぎ合わせ
-
複数のパスを結合したいが、オペレーティング システムが異なると異なるセパレータが使用される可能性がある場合。
-
現時点では、
path.join
関数を使用できます。
console.log(path.join('/user', 'why', 'abc.txt'));
ファイルとフォルダーを連結する
-
特定のファイルとフォルダーを結合したい場合は、
path.resolve
;を使用できます。-
resolve
この関数は、接続したパスの前に/
または が../
あるかどうかを判断します./
。 -
絶対パスがある場合は、対応するスプライス パスが返されます。
-
そうでない場合、パスは現在の実行ファイルが配置されているフォルダーと連結されます。
-
path.resolve('abc.txt'); // /Users/coderwhy/Desktop/Node/TestCode/04_learn_node/06_常见的内置模块/02_文件路径/abc.txt
path.resolve('/abc.txt'); // /abc.txt
path.resolve('/User/why', 'abc.txt'); // /User/why/abc.txt
path.resolve('User/why', 'abc.txt'); // /Users/coderwhy/Desktop/Node/TestCode/04_learn_node/06_常见的内置模块/02_文件路径/User/why/abc.txt
実際、これを webpack でも使用します。
const CracoLessPlugin = require('craco-less');
const path = require("path");
const resolve = dir => path.resolve(__dirname, dir);
module.exports = {
plugins: [
{
plugin: CracoLessPlugin,
options: {
lessLoaderOptions: {
lessOptions: {
modifyVars: { '@primary-color': '#1DA57A' },
javascriptEnabled: true,
},
},
},
}
],
webpack: {
alias: {
"@": resolve("src"),
"components": resolve("src/components")
}
}
}
2. 内蔵モジュール fs
1.1. fs モジュールについて知る
fsとはFile Systemの略でファイルシステムのことです。
サーバー側で機能する言語またはフレームワークには、通常、独自のファイル システムがあります。
-
サーバーはさまざまなデータ、ファイルなどをさまざまな場所に配置する必要があるためです。
-
たとえば、ユーザー データのほとんどはデータベースに保存される場合があります (後で説明します)。
-
たとえば、一部の構成ファイルまたはユーザー リソース (画像、オーディオ、ビデオ) は、オペレーティング システム上のファイルの形式で存在します。
ノードには独自のファイル システム操作モジュール (fs:) もあります。
-
Node によってカプセル化されたファイル システムの助けを借りて、任意のオペレーティング システム (ウィンドウ、Mac OS、Linux) 上でファイルを直接操作できます。
-
これが、Node がサーバーを開発できる理由の 1 つであり、Node がフロントエンド自動スクリプトなどの人気ツールになり得る理由の 1 つです。
Node ファイル システムには多くの API があります: https://nodejs.org/dist/latest-v14.x/docs/api/fs.html
-
私たちが一つ一つ学ぶことは不可能であり、その必要もありません。
-
これは、使用時にクエリできる API クエリのマニュアルとして使用する必要があります。
-
学習段階では、最も一般的に使用されるものだけを学習する必要があります。
ただし、これらの API のほとんどは、次の 3 つの操作モードを提供します。
-
方法 1: ファイルを同期的に操作します。コードはブロックされ、実行を継続しません。
-
方法 2: ファイルを操作するための非同期コールバック関数: コードはブロックされず、コールバック関数を渡す必要があります。結果が取得されると、コールバック関数が実行されます。
-
メソッド 3: 非同期 Promise オペレーション ファイル: コードはブロックされず、
fs.promises
メソッド オペレーションを呼び出すことによって Promise が返され、then と catch によって処理できます。
ここでは例としてファイルのステータスを取り上げます。
-
注: すべて
fs
モジュールをインポートする必要があります。
方法1: ファイルを同期操作する
// 1.方式一: 同步读取文件
const state = fs.readFileSync('../aaa.txt');
console.log(state);
console.log('后续代码执行');
//Hello World!
//后续代码执行
方法 2: 非同期コールバック関数を使用してファイルを操作する
fs.readFile(
'./aaa.txt',
{
encoding: 'utf8',
},
(err, state) => {
if (err) {
console.log(err);
return;
}
console.log(state);
}
);
console.log('后续代码执行');
//后续代码执行
//Hello World!
方法 3: 非同期 Promise 操作ファイル
fs.promises
.readFile('./aaa.txt', {
encoding: 'utf-8',
})
.then((res) => {
console.log('获取到结果:', res);
})
.catch((err) => {
console.log('发生了错误:', err);
});
1.2. ファイル記述子
ファイル記述子とは何ですか?
一般的なオペレーティング システムでは、カーネルはプロセスごとに、現在開いているファイルとリソースのテーブルを維持します。
-
開いているすべてのファイルには、ファイル記述子と呼ばれる単純な数値識別子が割り当てられます。
-
システム レベルでは、すべてのファイル システム操作でこれらのファイル記述子を使用して、特定の各ファイルを識別および追跡します。
-
Windows システムは、リソースを追跡するために、異なるものの概念的には同様のメカニズムを使用します。
-
ユーザーの作業を容易にするために、Node.js はオペレーティング システム間の特定の違いを抽象化し、開いているすべてのファイルに数値ファイル記述子を割り当てます。
fs.open()
メソッドは、新しいファイル記述子を割り当てるために使用されます。ファイル記述子を割り当てた後は、ファイルからのデータの読み取り、ファイルへのデータの書き込み、またはファイルに関する情報の要求に使用できます。
const fs = require('fs');
// 打开一个文件
fs.open('./bbb.txt', (err, fd) => {
if (err) {
console.log('打开文件错误:', err);
return;
}
// 1.获取文件描述符
console.log(fd);
// 2.读取到文件的信息
fs.fstat(fd, (err, stats) => {
if (err) return;
console.log(stats);
});
// 3.手动关闭文件
fs.close(fd, (err) => {
if (err) {
console.log(err);
}
});
});
1.3. ファイルの読み取りと書き込み
ファイルの内容を操作したい場合は、この時点でファイルの読み取りと書き込みを使用できます。
-
fs.readFile(path, [options], callback)
: ファイルの内容を読み取ります。 -
fs.writeFile(file, data,[options], callback)
: ファイルにコンテンツを書き込みます。
ファイルの書き込み:
fs.writeFile('../foo.txt', content, {}, err => {
console.log(err);
})
上記のコードでは、内容が何も入力されていない中かっこがあることがわかります。これは、次のように記述するときに入力されるオプション パラメーターです。
-
flag: 書き方。
-
エンコーディング: 文字エンコーディング;
まずフラグを見てみましょう。
-
flag には多くの値があります: https://nodejs.org/dist/latest-v14.x/docs/api/fs.html#fs_file_system_flags
-
w
書き込み用にファイルを開きます。デフォルト値。 -
w+
ファイルを読み取りおよび書き込み用に開きます。ファイルが存在しない場合はファイルを作成します。 -
r+
ファイルを読み取りおよび書き込み用に開き、ファイルが存在しない場合は例外をスローします。 -
r
読み取り用にファイルを開きます。読み取り時のデフォルト値。 -
a
書き込み用にファイルを開き、ファイルの最後にストリームを配置します。ファイルが存在しない場合は作成します。 -
a+
読み取りと書き込みのためにファイルを開き、ストリームをファイルの最後に配置します。ファイルが存在しない場合は作成します
-
エンコーディングをもう一度見てみましょう。
-
以前、Jianshu の文字エンコーディングに関する記事を書きました: https://www.jianshu.com/p/899e749be47c
-
現時点では、基本的に UTF-8 エンコーディングが使用されます。
読み取られたファイル:
-
エンコーディングが入力されていない場合、返される結果は Buffer です。
fs.readFile('./foo.txt', {encoding: 'utf-8'}, (err, data) => {
console.log(data);
})
1.4. フォルダーの操作
1.4.1 新しいフォルダーを作成する
新しいフォルダーを使用fs.mkdir()
または作成します。fs.mkdirSync()
const fs = require('fs');
const dirname = '../why';
if (!fs.existsSync(dirname)) {
fs.mkdir(dirname, (err) => {
console.log(err);
})
}
1.4.1 フォルダーを読み取る
フォルダー構造が表示されている場合
1. フォルダーの内容を読み取り、フォルダー内のファイルの文字列を取得します。 結果: [ 'aaa', 'bbb', 'nba.txt' ]
fs.readdir('./why', (err, files) => {
console.log(files)
})
2. フォルダーを読み取り、フォルダー内のファイルの情報を取得します
// 2.读取文件夹, 获取到文件夹中文件的信息
fs.readdir('./why', { withFileTypes: true }, (err, files) => {
console.log(files);
})
結果:2フォルダ1ファイル
[
ディレント { 名前: 'aaa', [シンボル(種類)]: 2 },
ディレント { 名前: 'bbb', [シンボル(種類)]: 2 },
ディレント { 名前: 'nba.txt', [シンボル(タイプ)]: 1 }
]
3. フォルダーの内容を再帰的に取得する
// 读取文件夹
function readFolders(folder) {
fs.readdir(folder, {withFileTypes: true} ,(err, files) => {
files.forEach(file => {
if (file.isDirectory()) {
const newFolder = path.resolve(dirname, file.name);
readFolders(newFolder);
} else {
console.log(file.name);
}
})
})
}
readFolders(dirname);
1.4.3 ファイル/フォルダーの名前変更
const fs = require('fs');
// 1.对文件夹进行重命名
fs.rename('./why', './kobe', (err) => {
console.log('重命名结果:', err);
});
// 2.对文件重命名
fs.rename('./ccc.txt', './ddd.txt', (err) => {
console.log('重命名结果:', err);
});
3. 組み込みモジュールイベント
3.1. 基本的な使い方
Node のコア API はすべて非同期イベントによって駆動されます。
-
このシステムでは、特定のオブジェクト (エミッター) がイベントを発行します。
-
このイベント (リスナー) をリッスンすることができ、コールバック関数が渡されます。このコールバック関数は、イベントがリッスンされるときに呼び出されます。
イベントの送信とイベントのリッスンは EventEmitter クラスを通じて行われ、それらはすべてイベント オブジェクトに属します。
-
emitter.on(eventName, listener)
: リスニング イベントも使用できますaddListener
。 -
emitter.off(eventName, listener)
: イベント リスナーを削除します。それを使用することもできますremoveListener
。 -
emitter.emit(eventName[, ...args])
: いくつかのパラメータを運ぶことができるイベントを送信します。
// events模块中的事件总线
const EventEmitter = require('events')
// 创建EventEmitter的实例
const emitter = new EventEmitter()
// 监听事件
//接收参数
function handleWhyFn(name, age, height) {
console.log('监听why的事件', name, age, height);
}
emitter.on('why', handleWhyFn)
// 发射事件
setTimeout(() => {
// 传递参数
emitter.emit('why', "coderwhy", 18, 1.88)
// 取消事件监听
emitter.off('why', handleWhyFn)
setTimeout(() => {
emitter.emit('why')
}, 1000)
}, 2000);
3.2. 一般的な方法
EventEmitter のインスタンスには、情報を記録できるいくつかのプロパティがあります。
-
emitter.eventNames()
:EventEmitter对象
現在登録されているイベント文字列の配列を返します。 -
emitter.getMaxListeners()
: 現在のEventEmitter对象
リスナーの最大数を返します。これは変更可能ですsetMaxListeners()
。デフォルトは 10 です。 -
emitter.listenerCount(事件名称)
:EventEmitter对象
現在のイベント名とリスナーの数を返します。 -
emitter.listeners(事件名称)
:EventEmitter对象
現在のイベント リスナーのすべてのリスナーの配列を返します。
const EventEmitter = require('events');
const bus = new EventEmitter();
bus.on('click', () => {});
bus.on('click', () => {});
bus.on('click', () => {});
bus.on('input', () => {});
// 1.获取所有监听事件的名称 [ 'click', 'input' ]
console.log(bus.eventNames());
// 2.获取监听最大的监听个数 10
console.log(bus.getMaxListeners());
// 3.获取某一个事件名称对应的监听器个数 3
console.log(bus.listenerCount('click'));
// 4.获取某一个事件名称对应的监听器函数(数组)
// [ [Function], [Function], [Function] ]
console.log(bus.listeners('click'));
3.3. メソッドの補足
emitter.once(eventName, listener)
: イベントを一度聞く
const EventEmitter = require('events');
const emitter = new EventEmitter();
emitter.once('click', (args) => {
console.log("监听到事件", args);
})
setTimeout(() => {
emitter.emit('click', 'coder');
emitter.emit('click', 'coder');
}, 2000);
emitter.prependListener()
: フロントバーにリスニングイベントを追加します。
emitter.on('click', (args) => {
console.log("a监听到事件", args);
})
// b监听事件会被放到前面
emitter.prependListener("click", (args) => {
console.log("b监听到事件", args);
})
emitter.prependOnceListener()
: リスニング イベントを先頭に追加しますが、一度だけリスニングします
emitter.prependOnceListener("click", (args) => {
console.log("c监听到事件", args);
})
emitter.removeAllListeners([eventName])
: すべてのリスナーを削除します
// 移除emitter上的所有事件监听
emitter.removeAllListeners();
// 移除emitter上的click事件监听
emitter.removeAllListeners("click");