Node fs模塊學習

1. fs模塊

  • 在Node.js中,使用fs模塊來實現全部有關文件及目錄的建立、寫入及刪除操做。
  • 在fs模塊中,全部的方法都分爲同步和異步兩種實現。
  • 具備sync後綴的方法爲同步方法,不具備sync後綴的方法爲異步方法。

2. 總體讀取文件

2.1 異步讀取

fs.readFile(path[, options], callback)
複製代碼
  • options
    • encoding
    • flag flag 默認 = 'r'

2.2 同步讀取

fs.readFileSync(path[, options])
複製代碼

3. 寫入文件

3.1 異步寫入

fs.writeFile(file, data[, options], callback)
複製代碼
  • options
    • encoding
    • flag flag 默認 = 'w'
    • mode 讀寫權限,默認爲0666
let fs = require('fs');
fs.writeFile('./1.txt',Date.now()+'\n',{flag:'a'},function(){
  console.log('ok');
});
複製代碼

3.2 同步寫入

fs.writeFileSync(file, data[, options])
複製代碼

3.3 追加文件

fs.appendFile(file, data[, options], callback)node

fs.appendFile('./1.txt',Date.now()+'\n',function(){
  console.log('ok');
})
複製代碼

3.4 拷貝文件

function copy(src,target){
  fs.readFile(src,function(err,data){
    fs.writeFile(target,data);
  })
}
複製代碼

4. 從指定位置處開始讀取文件

4.1 打開文件

fs.open(filename,flags,[mode],callback);linux

  •  filename, 必選參數,文件名 
  • * flags, 操做標識,如"r",讀方式打開  
  •  [mode],權限,如777,表示任何用戶讀寫可執行  
  •  callback 打開文件後回調函數,參數默認第一個err,第二個fd爲一個整數,表示打開文件返回的文件描述符,window中又稱文件句柄
fs.open('./1,txt','r',0600,function(err,fd){});
複製代碼

4.2 讀取文件

fs.read(fd, buffer, offset, length, position, callback((err, bytesRead, buffer)))算法

const fs=require('fs');
const path=require('path');
fs.open(path.join(__dirname,'1.txt'),'r',0o666,function (err,fd) {
    console.log(err);
    let buf = Buffer.alloc(6);
     fs.read(fd,buf,0,6,3,function(err, bytesRead, buffer){
       console.log(bytesRead);//6
       console.log(buffer===buf);//true
       console.log(buf.toString());
     })
})
複製代碼

4.3 寫入文件

fs.write(fd, buffer[, offset[, length[, position]]], callback)windows

const fs=require('fs');
const path=require('path');
fs.open(path.join(__dirname,'1.txt'),'w',0o666,function (err,fd) {
    console.log(err);
    let buf=Buffer.from('你好成都');
     fs.write(fd,buf,3,6,0,function(err, bytesWritten, buffer){
       console.log(bytesWritten);//6
       console.log(buffer===buf);//true
       console.log(buf.toString());//你好成都
     })
})
複製代碼

4.4 同步磁盤緩存

fs.fsync(fd,[callback]);promise

4.5 關閉文件

fs.close(fd,[callback]);緩存

let buf = Buffer.from('你好成都');
fs.open('./2.txt', 'w', function (err, fd) {
  fs.write(fd, buf, 3, 6, 0, function (err, written, buffer) {
    console.log(written);
    fs.fsync(fd, function (err) {
      fs.close(fd, function (err) {
          console.log('寫入完畢!')
        }
      );
    });
  })
});
複製代碼

4.6 拷貝文件

let BUFFER_SIZE=1;
const path=require('path');
const fs=require('fs');
function copy(src,dest,callback) {
    let buf=Buffer.alloc(BUFFER_SIZE);
    fs.open(src,'r',(err,readFd)=>{
        fs.open(dest,'w',(err,writeFd) => {
            !function read() {
                fs.read(readFd,buf,0,BUFFER_SIZE,null,(err,bytesRead) => {
                    bytesRead&&fs.write(writeFd,buf,0,bytesRead,read);
                });
            }()
        })
    });
}
copy(path.join(__dirname,'1.txt'),path.join(__dirname,'2.txt'),()=>console.log('ok'));
複製代碼

5 目錄操做

5.1 建立目錄

fs.mkdir(path[, mode], callback)bash

要求父目錄必須存在app

5.2 判斷一個文件是否有權限訪問

fs.access(path[, mode], callback)異步

fs.access('/etc/passwd', fs.constants.R_OK | fs.constants.W_OK, (err) => {
  console.log(err ? 'no access!' : 'can read/write');
});
複製代碼

5.3 讀取目錄下全部的文件

fs.readdir(path[, options], callback)async

5.4 查看文件目錄信息

fs.stat(path, callback)

  • stats.isFile()
  • stats.isDirectory()
  • atime(Access Time)上次被讀取的時間。
  • ctime(State Change Time):屬性或內容上次被修改的時間。
  • mtime(Modified time):檔案的內容上次被修改的時間。

5.5 移動文件或目錄

fs.rename(oldPath, newPath, callback)
複製代碼

5.6 刪除文件

fs.unlink(path, callback)
複製代碼

5.7 截斷文件

fs.ftruncate(fd[, len], callback)
複製代碼
const fd = fs.openSync('temp.txt', 'r+');
// 截斷文件至前4個字節
fs.ftruncate(fd, 4, (err) => {
  console.log(fs.readFileSync('temp.txt', 'utf8'));
});
複製代碼

5.8 監視文件或目錄

fs.watchFile(filename[, options], listener)
複製代碼
let fs = require('fs');
fs.watchFile('1.txt', (curr, prev) => {
  //parse() 方法可解析一個日期時間字符串,並返回 1970/1/1 午夜距離該日期時間的毫秒數。
  if(Date.parse(prev.ctime)==0){
    console.log('建立');
  }else if(Date.parse(curr.ctime)==0){
    console.log('刪除');
  }else if(Date.parse(prev.ctime) != Date.parse(curr.ctime)){
    console.log('修改');
  }
});

複製代碼

6 遞歸建立目錄

6.1 同步建立目錄

let fs=require('fs');
let path=require('path');
function makepSync(dir) {
    let parts=dir.split(path.sep);
    for (let i=1;i<=parts.length;i++){
        let parent=parts.slice(0,i).join(path.sep);
        try {
            fs.accessSync(parent);
        } catch (error) {
            fs.mkdirSync(parent);
        }

    }
}
複製代碼

6.2 異步建立目錄

function makepAsync(dir,callback) {
    let parts=dir.split(path.sep);
    let i=1;
    function next() {
        if (i>parts.length)
            return callback&&callback();    
        let parent=parts.slice(0,i++).join(path.sep);
        fs.access(parent,err => {
            if (err) {
                fs.mkdir(parent,next);
            } else {
                next();
            }
        });
    }
    next();
}
複製代碼

6.3 Async+Await建立目錄

async function mkdir(parent) {
    return new Promise((resolve,reject) => {
        fs.mkdir(parent,err => {
            if (err) reject(err);
            else resolve();
        });
    });
}

async function access(parent) {
    return new Promise((resolve,reject) => {
        fs.access(parent,err => {
            if (err) reject(err);
            else resolve();
        });
    });
}
async function makepPromise(dir,callback) {
    let parts=dir.split(path.sep);
    for (let i=1;i<=parts.length;i++){
        let parent=parts.slice(0,i).join(path.sep);
        try {
            await access(parent);
        }catch(err) {
            await mkdir(parent);
        }

    }
}
複製代碼

7. 遞歸刪除目錄

7.1 同步刪除目錄(深度優先)

let fs=require('fs');
let path=require('path')
function rmSync(dir) {
    try {
        let stat = fs.statSync(dir);
        if (stat.isFile()) {
            fs.unlinkSync(dir);
        } else {
            let files=fs.readdirSync(dir);
            files
                .map(file => path.join(dir,file))
                .forEach(item=>rmSync(item));
            fs.rmdirSync(dir);
        }
    } catch (e) {
        console.log('刪除失敗!');
    }
}
rmSync(path.join(__dirname,'a'));
複製代碼

7.2 異步刪除非空目錄(Promise版)

function rmPromise(dir) {
    return new Promise((resolve,reject) => {
        fs.stat(dir,(err,stat) => {
            if (err) return reject(err);
            if (stat.isDirectory()) {
                fs.readdir(dir,(err,files) => {
                    let paths = files.map(file => path.join(dir,file));
                    let promises = paths.map(p=>rmPromise(p));
                    Promise.all(promises).then((() => fs.rmdir(dir,resolve)));
                });
            } else {
                fs.unlink(dir,resolve);
            }
        });
    });
}
rmPromise(path.join(__dirname,'a')).then(() => {
    console.log('刪除成功');
})
複製代碼

7.3 異步串行刪除目錄(深度優先)

function rmAsyncSeries(dir,callback) {
    setTimeout(() => {
        fs.stat(dir,(err,stat) => {
            if (err) return callback(err);
            if (stat.isDirectory()) {
                fs.readdir(dir,(err,files) => {
                    let paths = files.map(file => path.join(dir,file));
                    function next(index) {
                        if (index>=files.length) return fs.rmdir(dir,callback);
                        let current=paths[index];
                        rmAsyncSeries(current,()=>next(index+1));
                    }
                    next(0);
                });
            } else {
                fs.unlink(dir,callback);
            }
        })
    },1000);
}

console.time('cost');
rmAsyncSeries(path.join(__dirname,'a'),err => {
     console.timeEnd('cost');
})
複製代碼

7.4 異步並行刪除目錄(深度優先)

function rmAsyncParallel(dir,callback) {
    setTimeout(() => {
        fs.stat(dir,(err,stat) => {
            if (err) return callback(err);
            if (stat.isDirectory()) {
                fs.readdir(dir,(err,files) => {
                    let paths=files.map(file => path.join(dir,file));
                    if (paths.length>0) {
                        let i=0;
                        function done() {
                            if (++i == paths.length) {
                                fs.rmdir(dir,callback);
                            }
                        }
                      paths.forEach(p=>rmAsyncParallel(p,done));
                    } else {
                        fs.rmdir(dir,callback);
                    }
                });
            } else {
                fs.unlink(dir,callback);
            }
        })
    },1000);
}
console.time('cost');
rmAsyncParallel(path.join(__dirname,'a'),err => {
     console.timeEnd('cost');
})
複製代碼

7.5 同步刪除目錄(廣度優先)

function rmSync(dir){
    let arr=[dir];
    let index=0;
    while (arr[index]) {
        let current=arr[index++];
        let stat=fs.statSync(current);
        if (stat.isDirectory()) {
            let dirs=fs.readdirSync(current);
            arr=[...arr,...dirs.map(d => path.join(current,d))];
        }
    }
    let item;
    while (null != (item = arr.pop())) {
        let stat = fs.statSync(item);
        if (stat.isDirectory()) {
            fs.rmdirSync(item);
        } else {
            fs.unlinkSync(item);
        }
    }
}
複製代碼

7.6 異步刪除目錄(廣度優先)

function rmdirWideAsync(dir,callback){
    let dirs=[dir];
    let index=0;
    function rmdir() {
        let current = dirs.pop();
        if (current) {
            fs.stat(current,(err,stat) => {
                if (stat.isDirectory()) {
                    fs.rmdir(current,rmdir);
                } else {
                    fs.unlink(current,rmdir);
                }
            });
        }
    }
    !function next() {
        let current=dirs[index++];
        if (current) {
            fs.stat(current,(err,stat) => {
                if (err) callback(err);
                if (stat.isDirectory()) {
                    fs.readdir(current,(err,files) => {
                        dirs=[...dirs,...files.map(item => path.join(current,item))];
                        next();
                    });
                } else {
                    next();
                }
            });
        } else {
            rmdir();
        }

    }();
}
複製代碼

8. 遍歷算法

  • 目錄是一個樹狀結構,在遍歷時通常使用深度優先+先序遍歷算法
  • 深度優先,意味着到達一個節點後,首先接着遍歷子節點而不是鄰居節點
  • 先序遍歷,意味着首次到達了某節點就算遍歷完成,而不是最後一次返回某節點纔算數
  • 所以使用這種遍歷方式時,下邊這棵樹的遍歷順序是A > B > D > E > C > F。
    A
           / \
          B   C
         / \   \
        D   E   F
    複製代碼

    8.1 同步深度優先+先序遍歷

    function deepSync(dir){
      console.log(dir);
      fs.readdirSync(dir).forEach(file=>{
          let child = path.join(dir,file);
          let stat = fs.statSync(child);
          if(stat.isDirectory()){
              deepSync(child);
          }else{
              console.log(child);
          }
      });
    }
    複製代碼

    8.2 異步深度優先+先序遍歷

    function deep(dir,callback) {
      console.log(dir);
      fs.readdir(dir,(err,files)=>{
          !function next(index){
              if(index == files.length){
                  return callback();
              }
              let child = path.join(dir,files[index]);
              fs.stat(child,(err,stat)=>{
                  if(stat.isDirectory()){
                      deep(child,()=>next(index+1));
                  }else{
                      console.log(child);
                      next(index+1);
                  }
              })
          }(0)
      })
    }
    複製代碼

    8.3 同步廣度優先+先序遍歷

    function wideSync(dir){
      let dirs = [dir];
      while(dirs.length>0){
          let current = dirs.shift();
          console.log(current);
          let stat = fs.statSync(current);
          if(stat.isDirectory()){
              let files = fs.readdirSync(current);
              files.forEach(item=>{
                  dirs.push(path.join(current,item));
              });
          }
      }
    }
    複製代碼

8.4 異步廣度優先+先序遍歷

// 異步廣度遍歷
function wide(dir, cb) {
    console.log(dir);
    cb && cb()
    fs.readdir(dir, (err, files) => {
        !function next(i){
            if(i>= files.length) return;
            let child = path.join(dir,files[i]);
            fs.stat(child,(err,stat)=>{
                if(stat.isDirectory()){
                    wide(child, () => next(i+1));
                } else {
                    console.log(child);
                    next(i+1);
                }
            })
        }(0);
    })
}
wide(path.join(__dirname,'a'));
複製代碼

8. path模塊

path是node中專門處理路徑的一個核心模塊

  • path.join 將多個參數值字符串結合爲一個路徑字符串
  • path.basename 獲取一個路徑中的文件名
  • path.extname 獲取一個路徑中的擴展名
  • path.sep 操做系統提定的文件分隔符
  • path.delimiter 屬性值爲系統指定的環境變量路徑分隔符
  • path.normalize 將非標準的路徑字符串轉化爲標準路徑字符串 特色:
    • 能夠解析 . 和 ..
    • 多個槓能夠轉換成一個槓
    • 在windows下反槓會轉化成正槓
    • 如結尾以槓結尾的,則保留斜槓
  • resolve
    • 以應用程序根目錄爲起點
    • 若是參數是普通字符串,則意思是當前目錄的下級目錄
    • 若是參數是.. 回到上一級目錄
    • 若是是/開頭表示一個絕對的根路徑
var path = require('path');
var fs = require('fs');
/**
 * normalize 將非標準化的路徑轉化成標準化的路徑
 * 1.解析. 和 ..
 * 2.多個斜槓會轉成一個斜槓
 * 3.window下的斜槓會轉成正斜槓
 * 4.若是以斜槓會保留
 **/

console.log(path.normalize('./a////b//..\\c//e//..//'));
//  \a\c\

//多個參數字符串合併成一個路徑 字符串
console.log(path.join(__dirname,'a','b'));

/**
 * resolve
 * 以就用程序爲根目錄,作爲起點,根據參數解析出一個絕對路徑
 *  1.以應用程序爲根起點
 *  2... .
 *  3. 普通 字符串表明子目錄
 *  4. /表明絕地路徑根目錄
 */
console.log(path.resolve());//空表明當前的目錄 路徑
console.log(path.resolve('a','/c'));// /a/b
// d:\c
//能夠獲取兩個路徑之間的相對關係
console.log(path.relative(__dirname,'/a'));
// a
//返回指定路徑的所在目錄
console.log(path.dirname(__filename)); // 9.path
console.log(path.dirname('./1.path.js'));//  9.path
//basename 獲取路徑中的文件名
console.log(path.basename(__filename));
console.log(path.basename(__filename,'.js'));
console.log(path.extname(__filename));

console.log(path.sep);//文件分隔符 window \ linux /
console.log(path.win32.sep);
console.log(path.posix.sep);
console.log(path.delimiter);//路徑 分隔符 window ; linux :
複製代碼

9. flags

符號 含義
r 讀文件,文件不存在報錯
r+ 讀取並寫入,文件不存在報錯
rs 同步讀取文件並忽略緩存
w 寫入文件,不存在則建立,存在則清空
wx 排它寫入文件
w+ 讀取並寫入文件,不存在則建立,存在則清空
wx+ 和w+相似,排他方式打開
a 追加寫入
ax 與a相似,排他方式寫入
a+ 讀取並追加寫入,不存在則建立
ax+ 做用與a+相似,可是以排他方式打開文件

10. 助記

  • r 讀取
  • w 寫入
  • s 同步
  • + 增長相反操做
  • x 排他方式
  • r+ w+的區別?
    • 當文件不存在時,r+不會建立,而會致使調用失敗,但w+會建立。
    • 若是文件存在,r+不會自動清空文件,但w+會自動把已有文件的內容清空。

11. linux權限 #


相關文章
相關標籤/搜索