目录
- 模块创建以及使用
- 文件模块的使用
- IO键盘交互
- URL解析
一、模块创建以及使用
- 什么是模块
模块和文件是一 一对应的,一个模块就是一个js文件,Node.js提供了exports和require两个对象,其中exports是模块公共的接口,require用于从外部获取一个模块的接口,即获取模块的exports对象。想要在外部用自定义模块中的方法exports方法暴露出去,通过require引入模块再调用其方法。 - 模块的分类
- 核心模块
如http、fs、path等,引用《深入浅出Node.js》中的一段话
核心模块部分在Node源代码的编译过程中,编译进了二进制执行文件。在Node进程启动时,部分核心模块就被直接加载进内存中,所以这部分核心模块引入时,文件定位和编译执行这两个步骤可以省略掉,并且在路径分析中优先判断,所以他的加载速度是最快的。
第三方模块
通过NPM安装的模块都会放入到node_modules目录下,在引用模块时和核心模块类似,require方法只需写模块名一就可以,不需要路径。Node在查找这个模块时会现在本级目录下查看是否有node_modules目录,若有看其内是否有相应的模块,若没有会去父目录查找,以此类推,就像是JavaScript的原型链和作用域链的查找方式。所以这类模块的查找会耗时最多,加载最慢。创建模块
第一种方式
//mymodule.js
//使用exports向外部暴露方法
var name;
exports.setName=function(isname) {
name = isname;
}
exports.sayNanme=function (){
console.log('hello my name is '+name);
}
//getmymodule.js
var myModule =require('./mymodule');
myModule.setName('AngelaMuller');//调用模块中方法设置属性
myModule.sayNanme();//调用方法
使用:
muller@ubuntu:~/node$ node getmymodule.js
hello my name is AngelaMuller
第二种方式
//mymodule.js
module.exports = function (name){
this.name = name;
this.sayhello = function(){
console.log('hello world!'+this.name);
}
};
//getmymodule.js
var person = require('./mymodule');
var oneper = new person('AngelaMuller');
oneper.sayhello();
使用:
muller@ubuntu:~/node$ node getmymodule.js
hello world!AngelaMuller
- 单次加载
上面的例子有点类似创建一个对象,但实际上和对象又有本质的区别,因为require不会重复加载模块,也就是说无论调用多少次require,获取的模块都是同一个 - 覆盖exports
有时我们知识想把一个对象封装到模块中,例如
定义模块:singleobejct.js
引入模块使用:getSingleObject.js
繁琐:exports.hello=hello;
引入:require("./singleobject").hello;
简易:module.exports=hello;
exports本身仅仅是一个普通的空对象,即{},它是专门用来声明接口
定义模块:singleobejct.js
function hello(){
var name;
this.setName=function(thyName){
name=thyName;
}
this.sayHello=function(){
console.log('hello '+name);
}
}
//exports.hello=hello;
module.exports=hello; // 定义的方法添加 (简单的方式)
引入模块使用:getSingleObject.js
var hello=require('./singleobject');
var he=new hello();
he.setName('marico'); //实例化第一个实例
he.sayHello();
var he2=new hello(); //实例化第二个实例
he2.setName('yfc');
he2.sayHello()
结果输出:
[root@localhost nodejs]# node getSingleObject.js
hello marico
hello yfc
繁琐:exports.hello=hello; //使用这种方式加载在对象中时,在调用使用时比较繁琐
引入:require("./singleobject").hello;
二、文件操作
node.js模块是文件操作的封装,它提供了文件的读取,写入,更名,删除,遍历目录,链接POSIX文件系统操作。与其他模块不同的是,fs模块中所有的操作都提供了异步和同步两个版本,例如,读取文件内容函数异步方法,readFile(),同步方法readFileSync().
- 同步方式的文件系统调用会导致阻塞,由于Node.js是单线程的,直到文件调用完成后,控制权才会被放回主线程,这也就导致了后台其他线程池中的很多线程不能够执行,从而导致Node.js中一定程度的性能问题。因此应该尽可能的减少使用同步方式的文件系统的方法调用。
- 异步调用会被主线程放置在事件队列中以备随后运行,这使得调用能够融入Node.js中的事件模型。但在执行代码时,就会变得有点棘手,因为事件并不能在预期的时候完成,这就需要有一个callback函数来规定当调用完成时需要完成的事。(这里可以去深入了解下Node.js的事件队列)
简单读取
fs.readFile(path,[options],callback);
fs.readFildSync(path,[options]);非简单读取
fs.read(fd,buffer,offset,length,position,callback);
fs.readSync(fd,buffer,offset,length,position);流式读取
fs.createReadStream(path,[options]);fs模块的其他方法
验证文件/目录路径的存在性
fs.exists(path,callback);
fs.existsSync(path);
注: 同步方法返回true/false,异步方法callback仅仅只有一个err对象表示是否删除成功。
同步读取
//引入fs模块
var fs=require('fs');
fs.readFile('content.txt','UTF-8',function(err,data){
if(err){
console.log(err);
}else{
console.log(data);
}
});
//没有回调函数
try{
var data=fs.readFileSync('content.txt','UTF-8');
console.log(data+"同步式读取");
}catch(e){
console.log(e)
}
content.txt 内容
Node.js的文件系统的Api AngelaMuller
输出结果:
muller@ubuntu:~/node$ node mymodule.js
Node.js的文件系统的Api AngelaMuller同步式读取
Node.js的文件系统的Api AngelaMuller
异步读取文件与readFile相同,而读取到的文件内容会以函数返回值的形式返回,如果有错误发生,fs将抛出异常,你需要try和catch捕获并处理异常。
Node.js from fs.readFileSync() to fs.readFile()
其他方法请查看官方API https://nodejs.org/dist/latest-v4.x/docs/api/fs.html
三、 IO交互
什么是IO交互
简单点是Node.js的控制台输入输出,I 是input 可读输入流 ,O是output 可输出流,Node.js也有如同C++和Java的标准输入输出进行交互。
- 输入设备
输入设备是人向计算机输入信息的设备,常用的输入设备有:
(1)键盘---人向计算机输入信息最基本的设备;
(2)鼠标器----一种光标指点设备;
(3)触摸屏----一种坐标定位设备,常用于公共查询系统。 - 输出设备
输出设备是直接向人提供计算机运行结果的设备,常用的输出设备有:
(1)显示器---计算机的主要输出设备,它与键盘一起构成最基本的人机对话环境;
(2)打印机---打印机为用户提供计算机信息的硬拷贝。常用的打印机有:击打式、喷墨式和激光打印机。
什么是Readline
Readline是Node.js里实现标准输入输出的封装好的模块,通过这个模块我们可以以逐行的方式读取数据流。
使用require("readline")可以引用模块。
如何使用Readline
// 引入readline模块
const readline = require('readline');
//创建readline接口实例
const rl = readline.createInterface({
input: process.stdin, //监听的可读流 (必填)
output: process.stdout //逐行读取(Readline)数据要写入的可写流(可选)
});
rl.setPrompt('What is your name ? > ');//设置提示符
rl.prompt(); //为用户输入准备好逐行读取(Readline),让用户有新的地方输入
rl.on('line', function (str) {
console.log('my name is : '+str);
});
// close事件监听
rl.on("close", function(){
// 结束程序
console.log('Have a great day!');
process.exit(0);// 结束程序
});
/* v0.10.44 版本似乎有问题 v4.5.0案例
rl.on('line', (line) => {
var str = line.trim();
console.log('my name is : '+str);
rl.prompt();
}).on('close', () => {
console.log('Have a great day!');
process.exit(0);
});
*/
在close事件的监听里,我们执行了process.exit(0)来使程序退出的操作,因为readline模块只要一开始获取用户输入就不会结束,必须使用这种直接的方式来结束程序。
输入与输出实例
// 引入readline模块
var readline = require('readline');
var rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
rl.on('line', function(line){
switch(line.trim()) {
case 'copy':
console.log("复制");
break;
case 'hello':
rl.write("Write");
console.log('world!');
break;
case 'close':
rl.close();
break;
default:
console.log('没有找到命令!');
break;
}
});
rl.on('close', function() {
console.log('bye bye');
process.exit(0);
});
'line'事件,这个事件就是在用户输完一行,按下回车后就会触发的事件,它会将用户输入的数据通过回调函数传回来,可在此方法里处理用户输入的数据
命令行输入与输出
const readline = require('readline');
const rl = readline.createInterface(process.stdin, process.stdout);
rl.setPrompt('OHAI> ');
rl.prompt();
rl.on('line', (line) => {
switch(line.trim()) {
case 'hello':
console.log('world!');
break;
default:
console.log('Say what? I might have heard `' + line.trim() + '`');
break;
}
rl.prompt();
}).on('close', () => {
console.log('Have a great day!');
process.exit(0);
});
四、URL解析
1.URL模块为URL的解析工具
var url = require('url');
var urlString = 'http://user:pass@best.bluepay.asia:90/p/a/t/h?query=string#hash';
var result = url.parse(urlString);
console.log(result);
//第二个可选参数设置为true时 query: { query: 'string' },
输出结果:
muller@ubuntu:~/node$ node url.js
Url {
protocol: 'http:',
slashes: true,
auth: 'user:pass',
host: 'best.bluepay.asia:90',
port: '90',
hostname: 'best.bluepay.asia',
hash: '#hash',
search: '?query=string',
query: 'query=string',
pathname: '/p/a/t/h',
path: '/p/a/t/h?query=string',
href: 'http://user:pass@best.bluepay.asia:90/p/a/t/h?query=string#hash' }
- href 属性会被忽略
- protocol无论是否有末尾的 : (冒号),会同样的处理 这些协议包括 http, https, ftp, gopher, file 后缀是
://
(冒号-斜杠-斜杠). 所有其他的协议如 mailto, xmpp, aim, sftp, foo, 等 会加上后缀 : (冒号) - auth 如果有将会出现.
- hostname 如果 host 属性没被定义,则会使用此属性.
- port 如果 host 属性没被定义,则会使用此属性.
- host 优先使用,将会替代 hostname 和port
- pathname 将会同样处理无论结尾是否有/ (斜杠)
- search 将会替代 query属性
- query (object类型; 详细请看 querystring) 如果没有 search,将会使用此属性.
- search 无论前面是否有 ? (问号),都会同样的处理
- hash无论前面是否有# (井号, 锚点),都会同样处理
2.queryString 模块
提供了实用程序来处理查询字符串
-
querystring.stringify(obj, [sep], [eq])
将JSON对象格式化为查询字符串格式的字符串,默认的分隔符为:“&”和“=”,具体可以看一下以下代码.
querystring.stringify({ foo: 'bar', baz: ['qux', 'quux'], corge: '' })
// returns 'foo=bar&baz=qux&baz=quux&corge='
querystring.stringify({foo: 'bar', baz: 'qux'}, ';', ':')
// returns 'foo:bar;baz:qux'
// Suppose gbkEncodeURIComponent function already exists,
// it can encode string with `gbk` encoding
querystring.stringify({ w: '中文', foo: 'bar' }, null, null,
{ encodeURIComponent: gbkEncodeURIComponent })
// returns 'w=%D6%D0%CE%C4&foo=bar'
-
querystring.parse(str, [sep], [eq], [options])
根据“&”和“=”将字符串进行分割,反序列化为JSON对象,而options包含的maxKeys默认设置为1000,如果将其设置为0则表示没这个限制.
querystring.parse('foo=bar&baz=qux&baz=quux&corge')
// returns { foo: 'bar', baz: ['qux', 'quux'], corge: '' }
// Suppose gbkDecodeURIComponent function already exists,
// it can decode `gbk` encoding string
querystring.parse('w=%D6%D0%CE%C4&foo=bar', null, null,
{ decodeURIComponent: gbkDecodeURIComponent })
// returns { w: '中文', foo: 'bar' }
-
querystring.escape,querystring.unescape
这两个内置方法,分别在上述两个方法的内置使用,如果有需要分别格式化和解码URL字符串。
3. QueryString模块和Url模块之间的关系
url.parse(string).query
|
url.parse(string).pathname |
| |
| |
------ -------------------
http://localhost:8888/start?foo=bar&hello=world
--- -----
| |
| |
querystring(string)["foo"] |
|
querystring(string)["hello"]
4. 获取静态资源
完整实例(根据不同的url地址请求不同的文件)
const ip = '192.168.1.223';//主机IP
const port = 3000;//端口号
//引入的组建模块 http、url、fs
const http = require('http');
const urls = require('url');
const fs = require('fs');
//实例化一个服务容器
var server = new http.Server();
//监听一个端口
server.listen(port , ip);
//注册一个事件处理的on方法
server.on('request' , function(req , res){
//获取请求的url地址
var url = urls.parse(req.url);
//console.log(url.pathname);
//根据path路径来读取不同的模板文件
switch( url.pathname ){
//显示首页
case '' || '/':
//读取文件内容
fs.readFile('./index.html',function( error, content){
if(error){
//如果有错误时,显示错误信息
funError();
}else{
//正确时浏览器输出模板文件的内容
funAuccess(res,content);
}
});
break;
//显示列表页面
case '/list':
fs.readFile('./list.html',function( error, content){
if(error){
funError(res , error);
}else{
funAuccess(res,content);
}
});
break;
//显示详情页
case '/show':
fs.readFile('./show.html',function( error, content){
if(error){
funError(res , error);
}else{
funAuccess(res,content);
}
});
break;
//获取静态资源的页面 如:css\js
default:
//获取文件名
var filename = url.pathname.substring(1);
//获取文件名对应的类型值
var type = getAllType( filename.substring(filename.lastIndexOf('.')+1));
//测试所用
//console.log(type);
//读取静态资源的页面
fs.readFile(filename , function( error, content){
if(error){
funError(res , error);
}else{
res.writeHead(200,{'Content-Type' : type});
res.write(content);
res.end();
}
});
break;
}
});
//错误提示的函数
function funError(response , error){
response.writeHead(400,{'Content-Type':'text/plain;charset="utf-8"'});
response.write(error.message);
response.end();
}
//正确时输出文件内容的函数
function funAuccess(response,cont){
response.writeHead(200,{'Content-Type':'text/html;charset="utf-8"'});//头信息
response.write(cont);//模板文件内容
response.end();
}
//定义文件类型的函数
function getAllType(code){
var type = '';
switch(code){
case 'html':
type = 'text/html;charset=utf-8';
break;
case 'js':
type = 'application/javascript/html;charset=utf-8';
break;
case 'css':
type = 'text/css;charset=utf-8';
break;
case 'text':
type = 'text/plain;charset=utf-8';
break;
case 'manifest':
type = 'text/cache-manifest;charset=utf-8';
break;
default:
type = 'application/octet-stream';
break;
}
return type;
}