Chinaunix首页 | 论坛 | 博客
  • 博客访问: 818852
  • 博文数量: 62
  • 博客积分: 526
  • 博客等级: 二等列兵
  • 技术积分: 2078
  • 用 户 组: 普通用户
  • 注册时间: 2012-02-04 20:41
个人简介

博客迁移至 freefe.cc

文章分类

全部博文(62)

分类: JavaScript

2014-03-09 18:26:02


    作为一名前端小丝,对于其他语言对文件的可操作性。默默的我们小前端是不是有点羡慕嫉妒恨呢,又默默的在浏览器调试窗口中 alert,console 了呢 T.T。

    于是,node中的文件操作给了我们光,这次就简单的来说说关于 node 中 File System的那档子事,本文主要包括了点操作文件的API,以及比较给力的 Stream 操作~,好了那么菜鸟留步,大牛请轻功飘过~

File System 

    关于文件操作,那么这边主要的就是 fs 这个模块。对于node中 fs 模块提供的API很多,但是其所有的方法均有同步和异步的形式。对于读取文件内容来说,最需要注意的一点就是异步与同步之间控制执行流程的问题~

  1. var fs = require('fs');
  2. // 使用异步回调的方式 因为是异步的,所以对于数据读取完后的操作我们需要使用回调的方式进行处理
  3. // 这点对于习惯事件操作的前端开发应该是习以为常的 。
  4. fs.readFile('data.json',function(err, data){
  5.   if(err){ }else{
  6.     console.log(data.length);
  7.    }
  8. });
结果:


    每个异步的API,都有其回调函数可以使用,那么对于下面的方式就会报错,就犹如在JS使用的setTimeout等类似,                                                      

  1. var fs = require('fs');
  2. //会有错 因为是异步读取文件 ,在console的时候数据还未读取出来
  3. var data = fs.readFile('data.json');
  4. console.log(data.length);
结果:


    或者干脆直接     使用其对应的同步API使用

  1. var fs = require('fs');
  2. // 或者改为同步的API读取
  3. var data = fs.readFileSync('data.json');
  4. console.log(data.length);
结果:


    其他一些简单的API

  1. fs.writeFile('delete.txt','1234567890',function(err){
  2.     console('youxi!');
  3. });

  4. // 删除文件
  5. fs.unlink('delete.txt', function(){
  6.  console.log('success');
  7. });

  8. // 修改文件名称
  9. fs.rename('delete.txt','anew.txt',function(err){
  10.  console.log('rename success');

  11.  // 查看文件状态
  12. fs.stat('anew.txt', function(err, stat){
  13.   console.log(stat);
  14.  });
  15. });

  16. // 判断文件是否存在
  17. fs.exists('a.txt', function( exists ){
  18.     console.log( exists );
  19. });


File System API


fs.open( path, flags,  [mode], callback );
flags为:
    'r' - 以只读方式打开文件,当文件不存在的时候发生异常
    'r+' - 以读写方式打开文件,当文件不存在的时候发生异常
    'rs' - 以只读方式同步打开文件,绕过本地缓存文件进行系统操作
    'rs+' - 以读写方式同步打开文件 ,绕过本地缓存文件进行系统操作
    'w' - 以只写方式打开文件,当文件不存在时创建文件,或者存在的时候覆盖文件
    'wx' - 与'w'一致,但只适用于文件不存在的时候( 测试的时候,,node版本为v0.10.26,如果文件不存在则正常创建文件并且写入数据,但是当文件不存在的时候,报错为必须要写上callback,加上callback后不报错但是不执行任何操作。 )
    'w+' - 以读写方式打开文件
    'ws+' - 与'w+'一致,但只适用于文件不存在的时候
    'a' - 以添加数据的方式打开文件,文件不存在则创建
    'a+' - 以添加和读取的方式打开文件,文件不存在则创建
    'ax+' - 与'a+'一致,但是存在的时候会失败

mode为:
    设置文件的模式,默认为 0666,可读可写。

callback:
    给出了两个参数 (  err, fd )


fs.readFile( filename, [optins], callback );
filename : String
option : Object
    encoding : String | Null, default = Null
    flag : String default = 'r'    
callback : Function
// callback 具有两个参数,( err, data ),和node中大部分回调接口类似。


fs.writeFile( filename, data,  [optins], callback );
filename : String
data : String | Buffer(之后会简单介绍)
option : Object
    encoding : String | Null, default = 'utf8'
    mode : Number default = 438
    flag : String default = 'w'    
callback : Function


// 将数据添加到文件末尾
fs.appendFile( filename, data,  [optins], callback );
filename : String
data : String | Buffer
option : Object
    encoding : String | Null, default = 'utf8'
    mode : Number default = 438
    flag : String default = 'w'    
callback : Function

以上比较常用的异步API 均有与之对应的同步API,在异步API后面加上Sync即是同步的API。更多的API请查看官方文档



Stream


    Stream可以算是node里的一出重头戏,与大数据处理方面有密切不可分的关系。

  1. var fs = require('fs');
  2. function copy( src, dest ){
  3.   fs.writeFileSync( dest, fs.readFileSync(src) );
  4.  }
  5. copy('data.json', 'dataStream.json');

    上面是一个对文件拷贝的代码,看似没什么问题,也的确在处理小文件的时候没什么大问题,但是一旦处理数量级很大的文件的时候可以看出,先将数据读取出来,在写入,内存作为中转,如果文件太大就会产生问题。

    在需要处理大文件的情况时,便要使用file system的另外几个API,createReadStream和fs.createWriteStream,将文件作为一块一块小的数据流进行处理,而不是一整块大型数据。

  1. // 也可能出现内存爆仓 写入数据跟不上读取速度 一直读取的文件不断放入内存中
  2. // 但是两个操作速度绝对是不一样的,于是未被写入的数据在内存中不断变大,就可能会导致内存的爆仓。
  3. var fs = require('fs');
  4. var rs = fs.createReadStream('data.json');
  5.  var ws = fs.createWriteStream('dataStream.json')
  6.  rs.on('data',function(chunk){
  7.   console.log('data chunk read ok');
  8.   times++;
  9.   ws.write(chunk,function(){
  10.    console.log('data chunk write ok');
  11.   });
  12.  });
  13.  rs.on('end',function(){
  14.   console.log(times);
  15.  });
结果:

这边可以看出对于读取和写入的速度不同,在最开始的时候读取完2块数据块后,第一块数据块写入才完毕,当累计很多之后势必会造成内存问题。所以对于流操作还需要改进一下

  1. var fs = require('fs');
  2. var rs = fs.createReadStream('data.json');
  3.  var ws = fs.createWriteStream('dataStream.json')
  4.  // eg 1 可以看数据流 drain事件表示为 只写数据流已将缓存里的数据写入目标
  5.  rs.on('data',function(chunk){
  6.   console.log('data chunk read ok');
  7.   if( ws.write(chunk,function(){
  8.     console.log('data chunk write ok')
  9.   }) == false ){
  10.    rs.pause()
  11.   }
  12.  });
  13.  rs.on('end',function(){
  14.   ws.end()
  15.  });
  16.  ws.on('drain',function(){
  17.   rs.resume();
  18.  });
结果:


或者:
  1. //eg2
  2.  function reStartRead( rs ){
  3.   console.log('lasted readed data write OK, reStart Read.');
  4.   rs.resume();
  5.  }
  6.  rs.on('data',function(chunk){
  7.   console.log('data chunk read ok' );
  8.   if( ws.write(chunk,function(){
  9.     reStartRead( rs );
  10.    }) == false ){
  11.    rs.pause()
  12.   }
  13.  });
  14.  rs.on('end',function(){
  15.   ws.end()
  16.  });
结果:


上面两个方式相当于每次读取完一块data块之后便暂停读取,直到该块写入已经完成才再次开启读取的stream。

对于这种情况 node里面有一个pipe的方法 连接两个数据流,犹如导管一样将数据读入写入

  1. function copy( src, dest ){
  2.   fs.createReadStream( src ).pipe( fs.createWriteStream( dest ) );
  3.  }
  4.  copy('data.json', 'dataStream.json');

上面使用到了 stream 里面的一些方法和事件,更多API内容请查看官网
阅读(29628) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~