目錄 (づ ̄ 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時還可以是字符串。
## 三種檔次類讀寫操作的比較
