欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

nodejs操作文件和数据流

程序员文章站 2022-05-02 12:22:02
前言 node中有一组流api,它们可以像处理网络流一样处理文件。流api用起来非常方便,本节学习介绍文件处理基础和流的概念。 目录 1. 处理文件路径 处理文件路径需要用到一个核心模块(path),path模块可以规范化、连接、解析路径,还可以将绝对路径转换为相对路径,提取路径的组成以及判断路径是 ......

前言

  node中有一组流api,它们可以像处理网络流一样处理文件。流api用起来非常方便,本节学习介绍文件处理基础和流的概念。

目录

  1. 处理文件路径
  2. fs核心模块简介
  3. 操作流
  4. 慢客户端问题

1. 处理文件路径

  处理文件路径需要用到一个核心模块(path),path模块可以规范化、连接、解析路径,还可以将绝对路径转换为相对路径,提取路径的组成以及判断路径是否存在。

1.1. 规范化路径

在存储和使用路径前最好能够将其进行规范化,这里使用path模块的normalize()函数

1 //规范化路径
2 var path=require('path');
3 path.normalize('/pathstudy//path1')
4 // =>'/pathstudy/path1'

 

1.2. 连接路径

通过path.join()函数可以连接多个路径字符串,如下所示:

1 //连接路径
2 var path=require('path');
3 path.join('/pathstudy','path1','test');
4 // => '/pathstudy/path1/test'

 

1.3. 解析路径

使用path.resolve()函数将多个路径解析为一个规范化的路径

1 //解析路径
2 var path=require('path');
3 path.resolve('/foo/bar','./dd');
4 // =>/foo/bar/dd
1.4. 提取路径的组成部分
1 //提取路径组成部分
2 var path=require('path');
3 path.dirname('/foo/bar/dd/a1.txt');//获取文件路径的目录 => /foo/bar/dd
4 path.basename('/foo/bar/dd/a1.txt');//获取文件名 => a1.txt
5 path.basename('/foo/bar/dd/a1.txt','.txt');//获取不包含文件类型的文件名 => a1
6 path.extname('/foo/bar/dd/a1.txt','.txt');//获取文件扩展类型 =>.txt
1.5. 判断路径是否存在

使用path.exists()函数判断路径是否存在,0.8版本以后使用fs.exists()函数代替,只需将导入模块替换为fs即可。

1 //判断路径是否存在
2 var path=require('path');
3 path.exists('/foo/bar/dd',function(exists){
4     console.log('是否存在:',exists);
5 })

2. fs模块简介

fs核心模块内置查询文件信息和打开/读写/关闭文件操作

查询文件信息

使用fs.stat()函数查询文件特征,例如大小、创建时间、权限等

//查询文件信息
var fs=require('fs');
fs.stat('/foo/bar/dd',function(stats){
    console.log(stats);//打印出文件信息
    stats.isfile();//判断是否文件
    stats.isdirectory();//判断是否目录
    stats.issocket();//判断是否unix套接字
    //...
});
打开/读写/关闭文件
nodejs操作文件和数据流
 1 var fs=require('fs');
 2 //打开文件,‘r’表示模式类型
 3 fs.open('/foo/bar/dd/a1.txt','r',function(err,fd){
 4     //获取文件描述符 fd
 5 });
 6 
 7 //读取文件
 8 fs.open('/foo/bar/dd/a1.txt','r',function(err,fd){
 9     if(err){
10         throw err;
11     }
12     var readbuffer=new buffer(1024),//设置缓冲区
13         bufferoffset=0,
14         fileposition=100,//从100字节开始
15         bufferlength=readbuffer.length;//读取随后的1024字节数据;
16         fs.read(fd,readbuffer,bufferoffset,bufferlength,fileposition,
17             function (err, readbytes){
18                 if(err){
19                     throw err;
20                 }
21                 if(readbytes>0){
22                     console.log(readbuffer.slice(0,readbytes));//获取读入缓冲区的字节数
23                 }
24             });
25 });
26 
27 //写入文件
28 fs.open('/foo/bar/dd/a1.txt','a',function(err,fd){
29     if(err){
30         throw err;
31     }
32     var writebuffer=new buffer('准备写入缓冲区的数据'),//设置缓冲区
33         bufferposition=0,//写入起始位置
34         fileposition=null,//从文件什么位置开始写 
35         bufferlength=readbuffer.length;//长度
36         fs.write(fd,writebuffer,bufferposition,bufferlength,fileposition,
37             function (err, write){
38                 if(err){
39                     throw err;
40                 }
41                 console.log('write bytes:',write);//获取读入缓冲区的字节数
42             });
43 });
44 
45 //关闭文件
46 fs.open('/foo/bar/dd/a1.txt','a',function(err,fd){
47     if(err){
48         throw err;
49     }
50     //write...
51     //close
52     fs.close(fd,function(){
53         //...
54     })
55 });
view code

文件模式类型:

r——数据流的位置从起始处打开文件读取

r+——数据流的位置从起始处打开文件读写

w——如果文件存在则清零,不存在则创建文件并写入数据,数据流的位置从文件起始处

w+——打开文件进行读写,如果文件存在则清零,不存在则创建文件并写入数据,数据流的位置从文件起始处

a——打开文件写入数据,如果文件存在则清零,不存在则创建文件,数据流的位置从文件结尾处,写操作都将追加到文件后面

a+——打开文件读写数据,如果文件存在则清零,不存在则创建文件,数据流的位置从文件结尾处,写操作都将追加到文件后面

需要注意,在读写文件操作回调函数执行之后,不要使用提供的缓冲区,不然可能会导致读写数据不完整。

3. 操作流

流是由几个node对象实现的抽象概念,创建或读取流的方式取决于使用流的类型,流的特性包含可读流可写流,通过监听data事件,在流每次提交数据时,都能够得到通知。

3.1. 创建文件系统流
 1 var fs=require('fs');
 2 //根据文件路径创建一个可读流
 3 fs.createreadstream('/foo/bar/file');
 4 
 5 fs.open('/foo/bar/file','r',function(err,fd){
 6     fs.createreadstream(null,{fd:fd,encoding:'utf8'});
 7     fs.on('data',function(data){
 8         console.log('data:',data);
 9     });
10 });
11 
12 //创建可写流
13 fs.createwritestream('/foo/bar/file');
14 
15 fs.createwritestream('/foo/bar/file',option);
16 //option表示第二个参数,默认值为{flags:'w',encoding:null,mode:0666}

 

可以指定createreadstream和createwritestream函数的第二个参数,用来设置文件的起始结束位置、编码格式等等,参数选项如下所示:

  • encoding——data事件发送的编码格式
  • fd——如果已经有一个打开文件描述符则可以传入该参数选项
  • buffersize——要被读取的每个文件块大小,单位是字节,默认64kb
  • start——设置文件中第一个被读取的字节位置,用来限制读取数据范围
  • end——与start相反
  • flags——表示用于打开文件的模式类型
  • mode——指定要打开文件的权限

4. 慢客户端问题

当客户端的网络连接速度较慢时,可写流也就慢速,可读流会快速产生data事件并监听,数据被发送到可写流,导致node不得不缓存数据导致缓冲区被快速填满。

一般情况可以通过暂停数据生产者来避免这个问题:

nodejs操作文件和数据流
 1 var http=require('http');
 2 var fs=require('fs');
 3 http.createserver(function(req,res){
 4     var rs= fs.createreadstream('/foo/bar/file');
 5 
 6     rs.on('data',function(data){
 7         if(!res.write(data)){
 8             rs.pause();//暂停可读流
 9         }
10     });
11 
12     rs.on('drain',function(){
13         rs.resume();//恢复可读流
14     });
15 
16     rs.on('end',function(){
17         res.end();//结束操作
18     });
19 
20 }).listen('8080');
view code

扩展:使用pipe函数操作上述暂停/恢复操作

nodejs操作文件和数据流
 1 var http=require('http');
 2 var fs=require('fs');
 3 http.createserver(function(req,res){
 4     var rs= fs.createreadstream('/foo/bar/file');
 5     rs.pipe(res);//由传输源调用并接受目标可写流作为参数
 6 }).listen('8080');
 7 
 8 http.createserver(function(req,res){
 9     var rs= fs.createreadstream('/foo/bar/file');
10     //默认情况下end()在可读流结束时在可写流上被调用,设置第二个参数end选项为false表示不让pipe函数进行end操作
11     rs.pipe(res,{end:false});
12 
13     rs.on('end',function(){
14         res.write('endend~~');
15         res.end();//结束操作
16     });
17 }).listen('8080');
view code

总结

对于流我表示比较懵逼,对概念理解的还不是很透彻。。