Node模块创建及使用,文件操作,IO交互,URL解析

目录

  • 模块创建以及使用
  • 文件模块的使用
  • 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;
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,743评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,296评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,285评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,485评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,581评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,821评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,960评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,719评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,186评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,516评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,650评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,329评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,936评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,757评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,991评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,370评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,527评论 2 349

推荐阅读更多精彩内容

  • Node.js是目前非常火热的技术,但是它的诞生经历却很奇特。 众所周知,在Netscape设计出JavaScri...
    w_zhuan阅读 3,610评论 2 41
  • 个人入门学习用笔记、不过多作为参考依据。如有错误欢迎斧正 目录 简书好像不支持锚点、复制搜索(反正也是写给我自己看...
    kirito_song阅读 2,458评论 1 37
  • Node.js是目前非常火热的技术,但是它的诞生经历却很奇特。 众所周知,在Netscape设计出JavaScri...
    Myselfyan阅读 4,066评论 2 58
  • topics: 1.The Node.js philosophy 2.The reactor pattern 3....
    宫若石阅读 1,064评论 0 1
  • 卷首 1. 爱情,如果要远离 别犹豫,快些离去吧 别让我等待中疲惫 2. 在手机的震动叮咚中 我原以为 每次都是你...
    可回阅读 220评论 2 2