NodeJs-fs模块

fs模块

1.在node中,与文件系统的交互是非常重要的,服务器的本质就是将本地的文件发送给远程的客户端。

2.Node通过fs模块来和文件系统进行交互。要使用fs模块,要先对它进行加载。

  • fs模块是一个核心模块,所以直接引入,不需要下载
var fs=require("fs");
  • 该模块提供了本地文件的读写能力,基本上是POSIX文件操作命令的简单包装。
  • 这模块几乎对所有操作提供异步和同步两种操作方式,供开发者选择。

同步文件系统会阻塞程序的执行,也就是除非操作完毕,否则不会向下执行代码。异步文件系统不会阻塞程序的执行,而是在操作完成时,通过回调函数将结果返回。

3.打开文件

  • 同步打开一个文件
fs.openSync(path,flags[,mode])
flags-文件打开的行为 
r 只读的
w 可写的
mode-设置文件模式(权限),文件创建默认权限为0666(可读可写),一般省略
var fs=require("fs");
var fd=fs.openSync("hello.txt","w");
  • 异步打开一个文件
fs.open(path,flags[,mode],calback(err,fd))
参数的含义跟上面的同步方式一样。
calback-回调函数,带有两个参数,第一个表示错误信息 err,第二个是文件对象。

在这里插入图片描述

4.文件中写入内容

  • 同步写入文件数据
fs.writeSync(fd,string[,position[,encoding]]);
-fd 文件的描述符,需要传递写入的文件的描述符
-string 要写入的内容
-position 表示写入文件开始位置
//操作文件之前先打开文件
var fs=fs.openSync("hello.txt","w");
//向文件中写入内容
fs.writeSync(fd,"hello world");
//使用完之后关闭文件
fs.closeSync(fd);
在我们演示的时候,不关闭文件似乎没啥影响,但是当我们在一台大型服务器(服务器一直在运行)上打开文件不关的时就会占用大量的内存,消耗大量的硬件资源。
  • 异步法将数据写入文件
fs.write(fd,data[,option],calback);
//writeFile直接打开文件默认是w模式,所以如果文件存在,该方法写入的内容会覆盖旧的文件内容。
fd-文件名或文件描述符
data-写入文件的数据,可以使String(字符串)或Buffer(缓冲)对象。
options-该参数是一个对象,包含{encoding,mode,flag}。默认编码为utf8,模式为0666,flag为"w"。flag为“a”,表示追加数据,不会覆盖之前的数据。
callback-回调函数,回调函数只包含错误信息参数(err),在写入失败时返回。
var fs=fs.open("test.txt","w",fucntion(err,fd){
	if(!err){
		fs.write(fd,"hello world",function(err,f){
            if(!err){
                console.log("文件写入成功");
            }else{
                console.log(err)
           }
           //关闭文件
			fs.close(fd,function(err){
				if(!err){console.log("文件已经关闭")}
			})
		}
	else{
		console.log(err);
	}
});

5.异步简单的文件写入(开发中常用的方式)

fs.writeFile(file, data[, options])
-file  要操作的文件的路径
-data  要写入的数据
-options 选项,可以对写入进行一些设置
	encoding <string> | <null> 默认值: 'utf8'
	mode <整数> 默认值: 0o666
	flag <string>参见对文件系统的支持flags。默认值: 'w'。
	signal <AbortSignal>允许中止正在进行的writeFile
-callback  当写入完成以后执行的函数
//引入fs模块   这个异步打开文件方式简单写法,需要手动打开文件
var fs=require("fs");
fs.writeFile("hello4.txt","这是通过write写入的内容"function(err){
	if(!err){
		console.log("写入成功")
	}
})
//默认情况下,文件的操作形式是“w”,文件不存在则创建,文件存在,如果里面由内容,则直接覆盖重写。
//下面我们换成操作符"a",表示向文件中追加内容。
var fs=require("fs");
fs.writeFile("hello3.txt","我是hell3.txt的文本内容",{flag:'a'},functiont(err){
		if(!err){
			console.log("写入成功!")
		}else{
			console.log(err);
		}
}){
}

当我们路径换成绝对路径时,完全可以替换路径的标识符\\\或者为/

6.流式文件写入

正常的文件写入,相当于将一个文件中的所有内容一次性的输送到文件中。当写入的时候,那么就如上面的那种写法一样,首先得要把全部的文件内容准备好,然后程序执行,再将内容慢慢输送到文件中。但这样容易造成内存溢出,也就是说文件内容太大,所以程序在执行的时候,要开辟好大的一块空间来存储要输送的文件内容。

所以同步、异步、简单文件的写入方式都不适合大文件的写入,性能较差,容易导致内存溢出。流式文件的写入,可以分步的,持续的给文件中写入内容。

fs.createWriteStream(path[, options])
-可以用来创建一个可写流
-path 文件路径
-options 配置的参数
var ws=fs.crteateWirteStream("hello3.txt");	
//通过ws向文件中输出内容  可以分多次写入文件
ws.write("通过可写流写入文件的内容");
ws.write("继续写入文件内容");
//可以通过监听流的open和close事件来监听流的打开和关闭
//on可以为对象绑定一个事件(事件字符串,回调函数)        once(事件字符串,回调函数)
//而流文件的打开只需要一次,所以在写文件的时候,文件会自动打开,从而触发下面的文件打开监听事件
//这里使用once监听事件,而不使用on事件。
ws.once("open",function(){
	console.log("流打开了");
})

上面说了流式文件的写入和文件打开时的事件监听,那么如何文件该如何关闭呢?

//文件在输送完数据之后,需要将文件关闭我们常规可能会想到使用ws.close()的方式关闭,但在这里并不合适正确的打开方式,请看下面:
//给文件流的关闭绑定一个监听事件
ws.once("close",function(){
	console.log("流关闭了");
})
ws.write("我写入文件内容1");
ws.write("我写入文件内容2");
//关闭流
ws.end();

7.简单文件读取(同步文件读取,异步文件读取和上面的写文件类似,程序的可读性不好,我们就不在演示了)

异步写法:fs.readFile(path[, options], callback)
同步写法:fs.readFileSync(path[, options])
 -path:要读取的文件路径
 -options 读取的选项
 -callbakc 回调函数,通过回调函数将读取到内容返回(err,data)
 	err 错误对象
 	data 读取到的数据,会返回一个Buffer。原因:因为读取的文件类型不确定,如果文件内容是一个图片或者音频则就无法将它以字符串类型输出。
var fs= require("fs");
fs.readFile("hello3.txt",function(err,data){
	if(!err){
		console.log(data);		//输出的是buffer数据
		console.log(data.toString())//如果数据是字符使用toString()转为字符串
	}
}
//读取文件的还有一个目的就是将它写出到另一个文件,下面我们将使用读写的方式将文件内容写入另一个文件
var fs=require("fs");
fs.readFile("hello.txt",function(err,data){
	if(!err){
		fs.writeFile("world.txt",data,function(err){
			if(!err){
				console.log("文件写入成功!");
			}
		})
	}
})

8.流式文件读取(适用于大文件)

如果文件太大,那么文件的保存又是一大问题。那么我们使用流式文件的方式读取,可以分多次将文件读取到内存中。

var fs=requrie("fs");
//创建一个可读流
var rs=fs.createReadStream("hello.jpg");
//创建一个可写流
var ws=fs.createWirteStream("world.jpg");
//监听流的开启和关闭
rs.once("open",function(){
	console.log("可读流打开了");
});
//可读流自动关闭
rs.once("close",function(){
	console.log("可读流关闭了");
    //数据读取完毕,关闭可写流
    ws.end();
});
ws.once("open",function(){
    console.log("可写流 文件打开了");
});
ws.once("close",function(){
    console.log("可写流,文件关闭了");
});

//如果要读取一个可读流中的数据,必须要为可读流绑定一个data事件,data事件绑定完毕,他会自动开始读取数据
rs.on("data",function(data){
   console.log(data);		//数据将会作为回调函数的参数返回。此时我们看到输出多条buffer数据
    //把数据写入可写流
    ws.write(data);
});

上面我们演示了如何打开一个可读流,并且将内容写入到可写流中,但是写法又是很繁杂的,下面介绍一种简单的写法

var fs=require("fs");
//创建一个可读流
var rs=fs.createReadStream("hello world1.mp3");
//创建一个可写流
var ws=fs.createWriteStream("hello world2.mp3");
//pipe()可将可读流中的内容,直接输到可写流中
rs.pipe(ws);

9.其他的操作

  1. 验证路径是否存在 可使用 fs.existsSync(path);
  2. 获取文件信息;
  • 同步获取文件状态 fs.stat("fs.html"\)

在这里插入图片描述

  • 文件的信息

在这里插入图片描述

文件信息Stats的属性和方法:

size : 文件大小; isFile():是否是一个文件 ; isDirectory():是否是一个文件夹 。。。。。

  • 异步获取文件信息 fs.stat("fs.html",function(err,stat){console.log(stat)}) ;stat中保留着文件的状态信息。

在这里插入图片描述

获取信息结果
在这里插入图片描述

10.删除文件

fs.unlink(path,callback) fs.unlinkSync(path)

11.读取一个目录

fs.readdir(path[,options],callback) fs.reddirSync(paht[,options])

​ -读取一个目录的目录结构 files是一个字符串数组,每一个元素就是一个文件夹或文件的名字

  • 异步读取文件夹

在这里插入图片描述

可以看出输出的结果是一个包含在数组当中的文件名;

在这里插入图片描述

12.截断文件

将文件修改为指定的大小,第二个参数表示字节大小,超过字节的部分被删除

fs.truncate(path,len,callback) fs.truncateSync(path,len)

13.创建文件夹

  • 同步法创建文件夹

在这里插入图片描述

  • 异步法创建文件夹

在这里插入图片描述

14.删除一个目录

fs.rmdir(path,callback) fs.rmdirSync(paht)\

15.对文件重命名

fs.rename(oldPath,newPath,callback) fs.renameSync(oldPath,newPath)

16.监视文件的修改

fs.watchFile(filename[,options],listener)
-监视文件的修改
-参数:filename  要监视的文件的名字
-options:配置选项
-listener 回调函数就,当文件发生变化的时候回调函数会执行
//其中curr,prev文件都是一个stat对象,保存了文件的状态信息
fs.watchFile("hello  world",function(curr,prev){
	console.log("修改前文件"+prev);
	console.log("修改后文件"+curr);
})

监听的工作原理:该方法会每隔一段时间检查文件的状态,一旦发生变化,则执行回调函数。工作原理我们知道了,但是

这里所说的一段时间又是多久呢?时间长了,无法及时监听到文件的变化,时间短了,会消耗系统资源。下面我们介绍option中的一个配置选项。

fs.watchFile("hello world",{inteval:1000},function(curr,prev){
	console.log("每隔一秒进行一次监听");
})

学过上面的内容,我们做一个实例

const fs=require("fs");
var path='./upload';
//查找一个目录,如果不存在创建该目录
fs.stat(path,(err,data)=>{
    if(err){
        //执行创建目录
        mkdir(path);
        return ;
    }
    //如果是一目录
    if(data.isDirectory()){
        console.log("upload目录存在");
    }else{
        //先删除再创建
        fs.unlink(path,(err)=>{
            if(!err){
                //执行创建目录
                mkdir(path);
            }else{
                console.log("创建失败");
            }
        })
    }
})
//文件创建函数
function mkdir(dir){
    fs.mkdir(dir,(err)=>{
        if(err){
            console.log(err);
            return ;
        }

    })
}

当然手动的创建一个目录似乎有点麻烦,接下来,我们使用第三方模块来实现文件夹的创建,实现和上面同样的效果。

1.安装 npm i mkdirp --save

2.使用

var mkdirp=require('mkdirp');
//创建一个文件夹
mkdirp("./upload",function(err){
	if(err){
		console.log(err);
	}
})

mkdirp的创建层级目录

mkdirp("./upload/aaa/xxx",function(err){
	if(err){
		console.log(err);
	}
})

上面我们知道可以使用fs.readdir()这个方法来读取一个目录,并且读取的所有内容都保存在一个数组中,但现在我们只想要将一个目录中的目录放入一个数组,又怎么实现呢?(使用异步方法操作文件)

var fs=require('fs');
var dirArr=[];
var path='./upload';
fs.readdir(paht,(err,data)=>{
	if(err){
		console.log(err);
		return ;
	}
    //使用递归法实现
	(function fn1(i){
        if(i<data.length){
             fs.stat(path+'/'+data[i],(err,data)=>{
          	  if(status.isDirectory(){
                 	dirArr.push(data[i]);
                 })
        	 fn1(++i);
        })
        else{
            console.log(dirArr)
           return ;
         }
        }    
    })(0)
})
//上面我们使用了递归法来获取了一个目录中的目录数组,但是代码可读性不高,下面我们使用async,await来处理异步
 var fs=require('fs');
 var path='./wwwroot';
 var dirArr=[];
 function getDir(data){
     //下面的回调函数定义为async
         fs.readdir(path,async (err,data)=>{
 			if(err){ console.log(err); return ;}
             //关键一步,使用循环的方式来实现多个异步过程
       		 for(var i=0;i<data.length;i++){
         		if(await fn1(path+'/'+data[i])){
                    dirArr.push(data[i]); 
                }   
        	  }
             //输出最后得到的目录数组
             console.log(dirArr);
 	}
 });
function fn1(data){
    return new Promise(funciton(resolve,reject){
              	fs.stat(data,(err,stats)=>{
        			if(err){
                        console.log(err);
                        //查看文件失败,返回给调用的await一个错误信息。
                        reject(err);
                        //提前结束本次异步过程
                        return ;
                    }
        			if(stats.isDirecotry()){
                        //其实这个地方已经就能判断出是否是目录了,之所以返回的是一个布尔值
                        //最重要的一个原因是降低代码之间的耦合度。这里你细细品!!!
                        resolve(true);
                    }else{resolve(false)}	
    			})         
              })
}

if(err){
                    console.log(err);
                    //查看文件失败,返回给调用的await一个错误信息。
                    reject(err);
                    //提前结束本次异步过程
                    return ;
                }
    			if(stats.isDirecotry()){
                    //其实这个地方已经就能判断出是否是目录了,之所以返回的是一个布尔值
                    //最重要的一个原因是降低代码之间的耦合度。这里你细细品!!!
                    resolve(true);
                }else{resolve(false)}	
			})         
          })

}


  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值