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

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

作者: 程序员有话说 | 来源:发表于2016-09-13 01:51 被阅读0次

    目录

    • 模块创建以及使用
    • 文件模块的使用
    • 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;
    }
    

    相关文章

      网友评论

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

          本文链接:https://www.haomeiwen.com/subject/ihhmettx.html