NodeJS簡易部落格系統(五)NodeJS入門學習(上)
一、模組
在NodeJS中,一般將程式碼合理拆分到不同的JS檔案中,每一個檔案就是一個模組,而檔案路徑就是模組名。在編寫每個模組時,都有require
、exports
、module
三個預先定義好的變數可供使用。
1、require
require
函式用於在當前模組中載入和使用別的模組,傳入一個模組名,返回一個模組匯出物件。模組名可使用相對路徑(以./
開頭),或者是絕對路徑(以/
或C:
之類的碟符開頭)。
2、exports
exports
物件是當前模組的匯出物件,用於匯出模組公有方法和屬性。別的模組通過require
函式使用當前模組時得到的就是當前模組的exports
物件。
3、module
通過module
物件可以訪問到當前模組的一些相關資訊,但最多的用途是替換當前模組的匯出物件。
4、模組初始化
一個模組中的JS程式碼僅在模組第一次被使用時執行一次,並在執行過程中初始化模組的匯出物件。之後,快取起來的匯出物件被重複利用。
5、主模組
通過命令列引數傳遞給NodeJS以啟動程式的模組被稱為主模組。主模組負責排程組成整個程式的其它模組完成工作。例如通過以下命令啟動程式時,main.js
就是主模組。
完整例子
有以下目錄:
- /home/user/hello/ - util/ counter.js main.js |
其中counter.js
內容如下:
var i = 0; function count() { exports.count = count; |
該模組內部定義了一個私有變數i,並在exports物件匯出了一個公有方法count。
主模組main.js
內容如下:
var counter1 = require('./util/counter'); console.log(counter1.count()); |
執行結果:
$ node main.js 1 2 3 |
二、檔案操作
1、檔案拷貝小例子
-
小檔案拷貝(同步,一次性讀取到記憶體)
var fs = require('fs'); function copy(src, dst) { function main(argv) { main(process.argv.slice(2)); |
-
大檔案拷貝(流)
var fs = require('fs'); function copy(src, dst) { function main(argv) { main(process.argv.slice(2)); |
2、常用
-
Buffer(資料塊)
var bin = new Buffer([ 0x68, 0x65, 0x6c, 0x6c, 0x6f ]); bin[0]; // => 0x68; var str = bin.toString('utf-8'); // => "hello" var bin = new Buffer('hello', 'utf-8'); // => <Buffer 68 65 6c 6c 6f> bin[0] = 0x48; [ 0x68, 0x65, 0x6c, 0x6c, 0x6f ] var bin = new Buffer([ 0x68, 0x65, 0x6c, 0x6c, 0x6f ]); sub[0] = 0x65; var bin = new Buffer([ 0x68, 0x65, 0x6c, 0x6c, 0x6f ]); bin.copy(dup); |
-
Stream(資料流)
當記憶體中無法一次裝下需要處理的資料時,或者一邊讀取一邊處理更加高效時,我們就需要用到資料流。NodeJS中通過各種Stream來提供對資料流的操作。 以上邊的大檔案拷貝程式為例,我們可以為資料來源建立一個只讀資料流,示例如下: var rs = fs.createReadStream(pathname); rs.on('data', function (chunk) { rs.on('end', function () { 上邊的程式碼中data事件會源源不斷地被觸發,不管doSomething函式是否處理得過來。程式碼可以繼續做如下改造,以解決這個問題。 var rs = fs.createReadStream(src); rs.on('data', function (chunk) { rs.on('end', function () { 此外,我們也可以為資料目標建立一個只寫資料流,示例如下: var rs = fs.createReadStream(src); rs.on('data', function (chunk) { rs.on('end', function () { var rs = fs.createReadStream(src); rs.on('data', function (chunk) { rs.on('end', function () { ws.on('drain', function () { |
-
File System(檔案系統)
NodeJS通過fs內建模組提供對檔案的操作。fs模組提供的API基本上可以分為以下三類: 檔案屬性讀寫。 其中常用的有fs.stat、fs.chmod、fs.chown等等。 檔案內容讀寫。 其中常用的有fs.readFile、fs.readdir、fs.writeFile、fs.mkdir等等。 底層檔案操作。 其中常用的有fs.open、fs.read、fs.write、fs.close等等。 NodeJS最精華的非同步IO模型在fs模組裡有著充分的體現,例如上邊提到的這些API都通過回撥函式傳遞結果。以fs.readFile為例: fs.readFile(pathname, function (err, data) { 此外,fs模組的所有非同步API都有對應的同步版本,用於無法使用非同步操作時,或者同步操作更方便時的情況。同步API除了方法名的末尾多了一個Sync之外,異常物件與執行結果的傳遞方式也有相應變化。同樣以fs.readFileSync為例: try { |
3、遍歷目錄
-
同步遍歷
function travel(dir, callback) { if (fs.statSync(pathname).isDirectory()) { - /home/user/ travel('/home/user', function (pathname) { ------------------------ |
-
非同步遍歷
function travel(dir, callback, finish) { fs.stat(pathname, function (err, stats) { |
4、文字編碼
-
BOM的移除
BOM用於標記一個文字檔案使用Unicode編碼,其本身是一個Unicode字元("\uFEFF"),位於文字檔案頭部。在不同的Unicode編碼下,BOM字元對應的二進位制位元組如下: Bytes Encoding function readText(pathname) { if (bin[0] === 0xEF && bin[1] === 0xBB && bin[2] === 0xBF) { return bin.toString('utf-8'); |
-
GBK轉UTF8
NodeJS支援在讀取文字檔案時,或者在Buffer轉換為字串時指定文字編碼,但遺憾的是,GBK編碼不在NodeJS自身支援範圍內。因此,一般我們藉助iconv-lite這個三方包來轉換編碼。使用NPM下載該包後,我們可以按下邊方式編寫一個讀取GBK文字檔案的函式。 var iconv = require('iconv-lite'); function readGBKText(pathname) { return iconv.decode(bin, 'gbk'); |
-
單位元組編碼
有時候,我們無法預知需要讀取的檔案採用哪種編碼,因此也就無法指定正確的編碼。比如我們要處理的某些CSS檔案中,有的用GBK編碼,有的用UTF8編碼。雖然可以一定程度可以根據檔案的位元組內容猜測出文字編碼,但這裡要介紹的是有些侷限,但是要簡單得多的一種技術。 首先我們知道,如果一個文字檔案只包含英文字元,比如Hello World,那無論用GBK編碼或是UTF8編碼讀取這個檔案都是沒問題的。這是因為在這些編碼下,ASCII0~128範圍內字元都使用相同的單位元組編碼。 反過來講,即使一個文字檔案中有中文等字元,如果我們需要處理的字元僅在ASCII0~128範圍內,比如除了註釋和字串以外的JS程式碼,我們就可以統一使用單位元組編碼來讀取檔案,不用關心檔案的實際編碼是GBK還是UTF8。以下示例說明了這種方法。 1. GBK編碼原始檔內容: NodeJS中自帶了一種binary編碼可以用來實現這個方法,因此在下例中,我們使用這種編碼來演示上例對應的程式碼該怎麼寫。 function replace(pathname) { |