• 深入基础(三)回调函数,文件处理


    回调函数

      其实想写一些关于回调函数的帖子的!但是..此处省略一万字, 我发现一些更加实用更应该注意到的事情,都知道nodejs是运行在服务端的js但是后端很多的encod啊decod操作是如何实现的关于编码格式如何实现的?

       而且都知道nodejs这东西本身对中文支持不是很好需要第三方库来完成针对中文数据的操作,本章会针对回调函数,中文转换,数据转码,深入讨论一下.

       言归正传,说起回调函数 对于有一定基础的前端开发童鞋来说并不陌生,或者说经常用到,所以我也不太想说太多直接上例子很简单的很好理解的如果理解上有所偏差还请各位看官指出来共同进步!

       

       前面那篇上述方式都有介绍过,老老实实吧代码敲一遍 然后自己运行一下看看结果就知道楼,就这么简单,这里我说一下我个人对回调函数理解:

          我自己总结就是异步处理与同步处理的区别,这也是处理并发的关键点之一,我可以同时请求A B两个任务而且不需要他们做出回应我就可以继续去做别的事儿等他们有反应了再来告诉我我再去处理,而同步就不一样了一就是一二就是二舅,这件事儿没完事儿别的啥都别想,两个方式各有各的优势,作用肯定不一样.

        当你输入input.txt里面是中文的时候就会发现控制台打印出来的居然是个空!这就引出了接下来这个问题中文转码!和编码转换! 都是干活 实际工作中经常用到的东西哟.

    文件处理

         如果你在上面的文件中输入的中文会出现控制台打印出来的中文是个空格!没错nodejs对中文支持并不好,不仅仅这样很多编码格式都是很欠缺的不过没关系!咱不是支持第三方库嘛添加就是喽.

            这里介绍了一些很基础的同步/异步文件读取,写入,文件复制操作还有很多方法比如文件监视watchFile,文件检查exists等等很多方式这就不一一介绍啦,想深入的孩砸看这里传送门-->http://www.w3cschool.cn/nodejs/hzpd1iti.html

            首先我想先解释一下上面哪个梨子,我不太喜欢成呐两种编码方式阻塞/非阻塞模式,同步写法与异步写法不是更加清晰吗,虽然说起来这么并不标准不仅仅是这样这里需要扩展一下这两个方法:

         readFileSync 

              同步文件读取,接收两个参数readFileSync(filename,[encoding])这里需要注意一下,filename并不只是文件名而是文件路径!,不要被上面的例子迷惑了而且针对文件类型方面我查了好久目前依然木有结果,希望对这方面熟悉的大神指引一下,这个方法解析文件有没有范围限制比如txt,js,php等等.encoding很明朗啦,文件编码,默认输出编码是buffer,上文例子中我的当前文件编码是utf-8,不要乱. 我引入的文件时utf-8编码的而输出的默认buffer,既然输出是buffer为啥控制台显示的确实正常的呢?

          toString

             这个方法也是可以接收参数滴toString([encoding],[strat],[end]),encoding默认转换编码是utf-8,不过放心并不支持gbk,gb2312,不信你试试 原生方法就是这么任性! strat 转换起始位置 end结束为止虽然看起来似乎很不方便但是如果你想base64一下这段文字soeasy了就.toString('base64') 然后就没有然后了.哦对了还有一点Buffer是node里面的默认交互数据类型(但是我不敢确认因为后面还没学到)下面附上toString源码:

    // toString(encoding, start=0, end=buffer.length)
    Buffer.prototype.toString = function(encoding, start, end) {
      var loweredCase = false;
      start = start >>> 0;
      end = util.isUndefined(end) ? this.length : end >>> 0;
      if (!encoding) encoding = 'utf8';
      if (start < 0) start = 0;
      if (end > this.length) end = this.length;
      if (end <= start) return '';
      while (true) {
        switch (encoding) {
          case 'hex':
            return this.hexSlice(start, end);
          case 'utf8':
          case 'utf-8':
            return this.utf8Slice(start, end);
          case 'ascii':
            return this.asciiSlice(start, end);
          case 'binary':
            return this.binarySlice(start, end);
          case 'base64':
            return this.base64Slice(start, end);
          case 'ucs2':
          case 'ucs-2':
          case 'utf16le':
          case 'utf-16le':
            return this.ucs2Slice(start, end);
          default:
            if (loweredCase)
              throw new TypeError('Unknown encoding: ' + encoding);
            encoding = (encoding + '').toLowerCase();
            loweredCase = true;
        }
      }
    };
    

      readFile

             异步读取文件,接收三个参数readFile(filename,[encoding],[options],callback(err,back))前两个我就不具体介绍啦,options里面有很多属性,包括encoding,mode,flag等等,代表具体文件信息,包括文件编码,文件模式,读写状态.最后这个说一下子 callback 回调函数喽 会返回err错误信息和back结果 如果木有找到返回null或者undefined函数嘛当然是个function了所以你可以在他异步的时候搞一些事情,也可以像同步一样等他有结果了再进行下去,当然返回的back就是文件内容如果你没做任何处理的话 Buffer 二进制编码...

            针对文件操作不光是读取当然还有写入操作,这里老规矩先看例子咱们一步步来分部解析:

    var fs=require("fs");
    
    //下面这两种write方式都会把之前的内容删除添加新内容
    //文件写入(同步)
    fs.writeFileSync("./data.txt","我同步写入的123xxx");
    //文件写入(异步1)
    fs.writeFile("./data.txt","我异步1写入123xxx");
    
    
    //文件写入(同步)append式不会删除之前内容而是继续添加
    fs.appendFileSync("./data.txt","我同步2写入的123xxx");
    //文件写入(异步2)
    fs.appendFile("./data.txt","我异步2写入123xxx")
    

      首先是文件写入的两种方式write和append,这两种是有区别滴,例子中我已经指出来啦,write 如果源文件有内容的话write会进行覆盖操作 吧新内容覆盖旧内容,旧内容就没啦,而append不一样他会一直添加在旧文件后面就这样一直加一直加..不影响源文件内容.儿相同的一点是如果文件夹内没有该文件的话两种方式都会创建该文件!

        writeFile/writeFileSync

        异步/同步文件写入操作,上面说过啦,如果文件不存在就会创建该文件,如果写入文件中有内容会覆盖旧内容..是覆盖啊!!fs.writeFile(filename,data,[options],callback(err)):

             filename:文件路径文件名

             data:写入内容

             options(写入属性):   encoding 文件编码 默认utf-8 ,  mode 文件读写权限(注意 number 纯数字) 默认0666 flags:读写模式 默认是w 这个太不好找到具体的了 而且网上关于这块的很少人去挖(这里提到这些属性并不代表是全部,很可能只是一小部分为了让大家认识到这一点)                               

                              flags可以为以下值:
                                      r:以读取模式打开文件
                                      r+:以读写模式打开文件
                                      w:以写入模式打开文件,如果文件不存在则创建
                                      w+:以读写模式打开文件,如果文件不存在则创建
                                      a:以追加模式打开文件,如果文件不存在则创建。
                                      a+:以读取追加模式打开文件,如果不存在则创建。
                              mode:用于创建文件时给文件指定权限,默认是0666,回调函数将会传递一个文件描述符fd
                             0666:文件权限值POSIX系统中对文件读取和访问权限的规范,通常用八进制数表示,如:0754标识文件所有者权限是7(读,写,执行),同组用户权限是5(读,执行)其他用户的权限是4(读)

               callback:回调函数 返回错误err    

          appendFile/appendFileSync      

          异步/同步写入操作参数用法参考writeFile/WriteFileSync  不过这里需要说明一下如果你想继续追加写入的话还是选择这个方法吧!因为他默认是追加写入而不是覆盖写入,但是! 如果你对node或者这个方法了解够深可以考虑一下改变mode和flags方式 达到自己的目的!

          createReadStream/createWriteStream

          针对大文件操作的时候往往成为各种程序自执行的难题,就像node中如果我想复制一个超大文件几GB那种甚至更大它是如何实现的呢?这里需要引入一个管道的概念:

          一般复制文件或者移动的时候程序会把文件先拿到内存中,然后再去创建一个新的文件地址去写入,但是这样做的时候内存很容易爆炸!,所以需要一条管道去引导完成这件事,我在其他博客中拿了点图过来用...自己画太难了

          

          这样看起来就好多了,node会先把一部分源文件一部分拿过来通过管道传递到新文件里面实际内存中只是占用了一条通道而已,并不是文件全部,理论知识到此结束!上代码(代码来自另外一位大神,亲测可用~)      

      Stream在nodejs中是EventEmitter的实现,并且有多种实现形式,例如:

    • http responses request
    • fs read write streams
    • zlib streams
    • tcp sockets
    • child process stdout and stderr

         下面是解决办法      

    var fs = require('fs');
    var readStream = fs.createReadStream('/path/to/source');
    var writeStream = fs.createWriteStream('/path/to/dest');
    
    readStream.on('data', function(chunk) { // 当有数据流出时,写入数据
        writeStream.write(chunk);
    });
    
    readStream.on('end', function() { // 当没有数据时,关闭数据流
        writeStream.end();
    });
    

      啧啧有点小问题,这样搞的话写入速度如果跟不上读取速度就会出现漏流问题,ok修改一下:

    var fs = require('fs');
    var readStream = fs.createReadStream('/path/to/source');
    var writeStream = fs.createWriteStream('/path/to/dest');
    
    readStream.on('data', function(chunk) { // 当有数据流出时,写入数据
        if (writeStream.write(chunk) === false) { // 如果没有写完,暂停读取流
            readStream.pause();
        }
    });
    
    writeStream.on('drain', function() { // 写完后,继续读取
        readStream.resume();
    });
    
    readStream.on('end', function() { // 当没有数据时,关闭数据流
        writeStream.end();
    });
    

      或者是直接用人家的方法:

    // pipe自动调用了data,end等事件
    fs.createReadStream('/path/to/source').pipe(fs.createWriteStream('/path/to/dest'));
    

      好啦这张暂时就先到这里吧!本来还想针对中文转码,buffer在深入一点的 后来分析内容有点太多啦 还是下章再来总结一下啦,我也是初学者希望大家共同交流共同进步,未来是扇门而技术是扇窗.

  • 相关阅读:
    关于Hadoop分组排序
    关闭Xshell Linux服务关闭问题
    Centos 7 mysql的安装
    通过 Thumbnails 压缩图片后转 base64
    Centos 7 java环境安装
    mysql 批量添加
    SpringCloud_服务提供者关闭,eureka还显示问题
    关于Hutool发送邮件
    Spring 定时任务 @Scheduled注解
    Listary快捷键和idea快捷键冲突问题
  • 原文地址:https://www.cnblogs.com/workstation-liunianguowang/p/6273654.html
Copyright © 2020-2023  润新知