目录 (づ ̄ 3 ̄)づ=>
[TOC]
## 引入
```
let fs = require('fs');
```
## 读操作
### fs.readFileSync(路径[,编码])
```
1.路径必须正确否则报错
2.默认为utf8方法
3.此方法为同步方法
let result = fs.readFileSync('./1.txt','utf8');
```
### fs.readFile(路径[,编码],callback)
```
回调是必须的,因为异步方法木有返回值,需通过回调取得值进行下一步操作
fs.readFile('index.js','utf8',function(err,data){ //err错误第一
if(err)return console.log(err);
// fs.readFile。。。
});
```
## 写操作
### fs.writeFileSync(path,data[,options],callback)
### fs.writeFile(path,data[,options],callback)
```
fs.writeFile('1.txt','{name:1,age:2}',function(err){
...
});
```
## 精度读/写操作
```
let fs = require('fs');
/**
* r 读取
* s 同步
* + 增加相反操作
* x 排他(我读的时候别人不能)
* r+ w+区别:当文件不存在时,r+不会创建,而会导致调用失败,但w+会创建
* 如果文件存在,r+不会自动清空文件,但w+会自动把已有文件的内容清空
* rs忽略缓存
* wx 排他写入
* a 追加写入
*/
/**
* chmod
*/
// fs.writeFile('./2.txt','data',{encoding:'base64',flag:'a',mode:0o666},function(err){
// console.log(err);
// });
// fs.appendFile('./2.txt','data',function(err){
// console.log(err);
// });
// fs.readFile('./2.txt',{encoding:'utf8',flag:'r'},function(err,data){
// console.log(data); //由于上面时base64写入的,这里用utf8解出来是乱码
// })
//----------------------------------
//以上都是把文件当成一个整体来操作的
//当文件特别大的时候,大于内存的时候是无法执行这样的操作的
//我们需要精确的控制读取的字节
//file descriptor 文件描述符
//每当打开一个文件,操作系统就给这个文件分配一个数字,代表这个文件
//0 标准输入 1标准输出 2错误输出
// process.stdin.on('data',function(data){ //标准输入
// console.log(data); //监听控制台输入 打印出来
// })
// process.stdout.write('hello');
// process.stderr.write('wrong');
fs.write(2,Buffer.from('a'),0,1,null,function(){
//0标准输入
//1向标准输出里写
//2向错误输出里写
//fd向文件里写
//没打开一个文件 描述符会+1
})
process.stdin.on('data',function(data){ //标准输入
console.log(data); //监听控制台输入 打印出来
})
// fs.open('./2.txt','r',0o666,function(err,fd){
// // console.log(fd);//3
// //read可以精确的读一个文件
// //buff读到哪个buff里 //偏移量读到buff的哪个位置 //length从文件读取几个字节 //position 从文件哪里开始读取 //不填表示当前位置 内部有一个指针
// //bytesRead 实际读到的字节
// let buff = Buffer.alloc(6);
// fs.read(fd,buff,0,3,null,function(err,bytesRead,buffer){ //buffer同buff
// console.log(buff.toString()); //123
// fs.read(fd,buff,3,3,null,function(err,bytesRead,buffer){ //buffer同buff
// console.log(buff.toString()); //123456
// })
// })
// })
fs.open('./2.txt','w',0o666,function(err,fd){
fs.write(fd,Buffer.from('a'),0,1,null,function(err,bytesWritten){
console.log(bytesWritten);
fs.fsync(fd,function(err){
fs.close(function(){
console.log('关闭')
})
})
})
})
```
### 精度写入时r+与a mod的区别
```
let fs = require('fs');
fs.open('./2.txt','r+',0o666,function(err,fd){
console.log(fd);
//offset length position
fs.write(fd,Buffer.from('嘿哈'),3,3,6,function(){
//如果mode为a,那么position是无效的
//要使position有效必须为r+
//position有3个的偏移 3代表可见位为0的索引的位置
})
})
```
### 读一点写一点
```
let fs = require('fs');
//实现节约内存的拷贝,读一点写一点
const BUFFER_SIZE = 3; //缓存大小为3个字节
function copy(src,target){
fs.open(src,'r',0o666,function(err,readFd){
fs.open(target,'w',0o666,function(err,writeFd){
let buff = Buffer.alloc(BUFFER_SIZE);
!function next(){
fs.read(readFd,buff,0,BUFFER_SIZE,null,function(err,bytesRead,buffer){
if(bytesRead<=0) return;
fs.write(writeFd,buff,0,bytesRead,null,next);
});
}();
})
})
}
copy('1.txt','2.txt'); //1拷贝到2
```
## 一个简单的copy文件方法实现
```
let fs = require('fs');
//同步copy方法
function copy(origin,target){
let result = fs.readFileSync(origin,'utf8');
fs.writeFileSync(target,result);
}
//异步copy方法
function copySync(origin,target){
fs.readFile(origin,'utf8',function(err,data){
if(err) console.log(err);
fs.writeFile(target,data,function(err){
if(err) console.log(err);
})
})
}
```
## 文件状态
```
fs.stat('1.txt',function(err,stats){
//若文件存在,stats为一个对象,err为null
//若不存在,stats为undefined,err为一个对象
console.log(stats);
console.log(stats.isFile()); //true
console.log(stats.isDirectory()); //false
})
>>>
Stats {
dev: 1002684,
mode: 33206,
nlink: 1,
uid: 0,
gid: 0,
rdev: 0,
blksize: undefined,
ino: 562949953725509,
size: 26,
blocks: undefined,
atimeMs: 1515755716214.5186,
mtimeMs: 1515755716216.5188,
ctimeMs: 1515755716334.5254,
birthtimeMs: 1515755319871.849,
atime: 2018-01-12T11:15:16.215Z,
mtime: 2018-01-12T11:15:16.217Z,
ctime: 2018-01-12T11:15:16.335Z, //ctime触发的范围比mtime更广
birthtime: 2018-01-12T11:08:39.872Z }
```
## 递归创建/删除文件夹及文件
利用stat判断文件是否存在
```
let fs = require('fs');
function mkdirp (url){
//??分隔符是哪个
let urlArr = url.split('/'),
index = 0;
mkdir(urlArr[index]);
function mkdir(path){
if(index>urlArr.length)return;
fs.stat(path,function(err,stats){
if(err){ //说明文件不存在需要创建
fs.mkdir(path,function(err){
if(err) return console.log(err);
mkdir(urlArr.slice(0,++index).join('/'));
})
}else{ //说明已经存在跳过创建继续查看下一级
mkdir(urlArr.slice(0,++index).join('/'));
}
});
}
}
fs.mkdir('mkdir1',function(err){
console.log(err);
});
mkdirp('a/b/c/d');
```
利用access判断文件是否存在
```
//如何创建目录
let fs = require('fs');
//当创建目录的时候必须要求父目录是存在的
// fs.mkdir('a/b',function(err){
// console.log(err);
// })
//判断一个文件或目录 是否存在 fs.exists(已废弃)
// fs.access('a',fs.constants.R_OK,function(err){
// console.log(err);
// })
/**
* 递归异步创建目录
* @param dir
*/
function mkdirp(dir){
let paths = dir.split('/'); // [a,b,c]
!function next(index){
if(index > paths.length) return;
let current = paths.slice(0,index).join('/'); //第一次0,1 为a
fs.access(current,fs.constants.R_OK,function(err){
if(err){
fs.mkdir(current,0o666,()=>next(index+1));
}else{
next(index+1);
}
})
}(1);
}
mkdirp('a/b/c');
// //获取一个目录下面的所有文件或目录
// fs.readdir();
// //删除一个文件
// fs.unlink(path);
// //删除一个空目录(目录里有东西删不了)
// fs.rmdir('a');
/**
* 同步递归删除
* @param dir
*/
function rmdirpSync(dir){
let files = fs.readdirSync(dir);
files.forEach(function(file){
let current = dir+'/'+file
,child = fs.statSync(current);
if(child.isDirectory()){
rmdirp(current);
}else{
fs.unlinkSync(current);
}
});
//删除本目录下的文件后删除自己
fs.rmdirSync(dir);
}
rmdirpSync('a')
```
异步递归删除
```
function rmDirAsync(dir,callback) {
fs.readdir(dir, 'utf8', function (err, files) {
!function next(index) {
if (err) return console.error(err);
if (files.length == 0 || index >= files.length) {
fs.rmdir(dir, function (err) {
if (err) console.error(err);
callback && callback();
});
} else {
let childPath = path.join(dir,files[index])
fs.stat(childPath, function (err, stats) {
if (err) {
console.error(err);
return reject(err);
}
if (stats.isDirectory()) {
rmDirAsync(childPath,()=>next(index+1))
} else{
fs.unlink(childPath, function (err) {
if (err) {
console.error(err);
}
next(index + 1);
});
}
})
}
}(0);
});
}
```
## API记忆
- readFile/writeFile 区别在于 writeFile 的 `options` 参数中多了一个 `mode`
- readFile没有指定编码时读取出来的是buffer,注意:如果一个文件描述符被指定为 path,则它不会被自动关闭。
- writeFile 如果 data 是一个 buffer,则忽略 encoding 选项。它默认为 'utf8',data 可以是一个字符串或一个 buffer。
- xxFile 和 read/write 的区别在于,不能单独使用read/write 必须配合 `fs.open` 打开文件先,且 `options` 参数中的 `flag` [,mode] 给了 `open`,自己只保留 `encoding`。
- write(string)和 write(buffer)的区别在于write(string)可配置 `encoding`
- read 和 write 的区别在 read没有encoding,因为read的单位只能是buffer,而write时还可以是字符串。
## 三种档次类读写操作的比较
![](https://box.kancloud.cn/95893dcc490e5b897fdc921f3c81eb82_1831x1039.png)