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) { |