Node.js學習二(fs 檔案系統)

2022-01-12 23:00:02


一、什麼是fs檔案系統模組

fs模組是Node.js官方提供的,用來操作檔案的模組。它提供了一系列的方法和屬性,用來滿足使用者對檔案的操作需求。

使用fs模組操作檔案時,需要先匯入它,程式碼如下:

const fs = require(‘fs’)

二、同步與非同步

(1)同步:程式在涉及到檔案IO時,必須等到檔案IO操作結束後再執行後續的操作。

(2)非同步:程式在涉及到檔案IO時,不等待檔案IO操作結束,繼續執行後續的操作,當檔案IO操作結束後系統會通知程式處理檔案IO的結果。

所有檔案系統操作都具有同步和非同步形式,供開發者選擇。
非同步的形式總是將完成回撥作為其最後一個引數。傳給完成回撥的引數取決於具體方法,但第一個引數始終預留用於異常。如果操作成功完成,則第一個引數是null或undefined。

三、回撥函數

所謂「回撥」,就是」回頭再調」。回撥函數並不是馬上呼叫,而是需要等到事件觸發了以後再執行。回撥是一個非同步等效的功能,在完成特定任務後回撥函數被呼叫。

四、讀取指定檔案中的內容

1、fs.readFile()

用於非同步讀取資料。 - - - - 也叫非阻塞方式讀

語法格式如下:

fs.readFile(path[,options],callback);

path:必選引數,字串,表示檔案的路徑,可以是絕對路徑,也可以是相對路徑。注意,如果是相對路徑,是相對於當前程序所在的路徑(process.cwd()),而不是相對於當前指令碼所在的路徑。
option:可選引數,表示以什麼編碼格式來讀取檔案
callback:必選引數,檔案讀取完成後,通過回撥函數拿到讀取的結果,該函數的第一個引數是發生錯誤時的錯誤物件,第二個引數是代表檔案內容的Buffer範例。
舉例如下:

//匯入fs模組
const fs = require('fs');
//呼叫readFile()方法讀取檔案
fs.readFile('./fs1.txt','utf8',function(err,dataStr){
   	console.log(err);
   	console.log('-----');
   	console.log(dataStr);
});
console.log('非同步讀取檔案')
//err代表列印失敗後的結果,dataStr代表列印成功後的結果

成功時的結果如下:
在這裡插入圖片描述

此時err為null,dataStr為列印出的結果,且我們可以發現,先列印出了「非同步讀取檔案」的結果,這就可以看出fs.readFile()用於非同步讀取資料的特性,在涉及到檔案IO時,它不等待檔案IO操作結束,會繼續執行後續的操作,當檔案IO操作結束後系統會通知程式處理檔案IO的結果。

失敗後的結果如下,此時我們故意寫一個錯誤的檔名。
在這裡插入圖片描述

則err會列印出錯誤物件,dataStr結果為undefined

2、判斷檔案是否讀取成功

可以通過err物件是否為null,從而判斷檔案讀取的結果。

//判斷檔案是否讀取成功
//匯入fs模組
const fs = require('fs');
fs.readFile('./fs1.txt','utf8',function (err,result){
    if(err){
        console.log('讀取失敗:'+err.message)
    }else{
        console.log('讀取成功')
        console.log(result)
    }
})

讀取成功時列印結果如下:
在這裡插入圖片描述

讀取失敗時結果如下:
在這裡插入圖片描述

3、readFileSync()

用於同步讀取檔案,返回一個字串。- - - -阻塞方式

語法格式如下:

fs.readFileSync(path[, options]);

readFileSync方法的第一個引數是檔案路徑,第二個引數可以是一個表示設定的物件,也可以是一個表示文字檔案編碼的字串。預設的設定物件是{ encoding: null, flag: ‘r’ },即檔案編碼預設為null,讀取模式預設為r(唯讀)。如果第二個引數不指定編碼(encoding),readFileSync方法返回一個Buffer範例,否則返回的是一個字串。
舉例如下:

//同步讀取檔案
const fs = require('fs');
const str = fs.readFileSync('./fs1.txt','utf8');
console.log(str);
console.log('同步讀取檔案');

結果如下:
在這裡插入圖片描述

可以發現它同步方式處理資料的特性,先等待檔案IO操作結束,返回其結果,再接著往下處理程式。

五、向指定的檔案中寫入內容

1、fs.writeFile()

非同步寫入檔案,如果檔案已經存在將會覆蓋檔案
語法格式:

fs.writeFile(file,data[,option],callback);

file:必選引數,需要指定一個檔案路徑的字串,表示檔案的存放路徑
data:必選引數,表示要寫入的內容
option:可選引數,表示以什麼格式寫入檔案內容,預設值是utf8
callback:必選引數,檔案寫入完成後的回撥函數,回撥函數獲取一個引數err,用於在發生任何寫入錯誤時返回錯誤。
舉例如下:

//匯入fs模組
const fs = require('fs');
//呼叫fs.writeFile()方法,寫入檔案的內容
fs.writeFile('f://ds','我愛北京天安門','utf8',function (err){
    if(err){
        console.log('寫入失敗:'+err.message)
    }else{
        console.log('寫入成功')
        fs.readFile('./fs1.txt','utf8',function (e,result){
            if(e){
                return '讀取失敗'+e.message
            }else{
                console.log(result)
            }
        })
    }
})

在上述程式碼中,我們指定寫入檔案的路徑在F槽裡,可是本電腦是沒有F槽的,所以寫入失敗,列印出錯誤資訊。
在這裡插入圖片描述

//匯入fs模組
const fs = require('fs');
//呼叫fs.writeFile()方法,寫入檔案的內容
fs.writeFile('./fs1.txt','我愛北京天安門','utf8',function (err){
    if(err){
        console.log('寫入失敗:'+err.message)
    }else{
        console.log('寫入成功')
		console.log('此時的錯誤為:',err)
        fs.readFile('./fs1.txt','utf8',function (e,result){
            if(e){
                console.log('讀取失敗'+e.message)
            }else{
                console.log(result)
            }
        })
    }
})

這個程式碼路徑正確,按照程式來講,它會列印出寫入成功,然後列印出當成功時err被定義為null,最後讀取出寫入的資訊
在這裡插入圖片描述

2、判斷檔案是否寫入成功

可以判斷err物件是否為null,來判斷檔案是否寫入成功。

//匯入fs模組
const fs = require('fs');
//呼叫fs.writeFile()方法,寫入檔案的內容
fs.writeFile('f://fs1.txt','天安門上太陽升',function (err){
    if(err){
        return console.log('檔案寫入失敗:'+err)
    }else{
        console.log('檔案寫入成功')
    }
});

此時錯誤,err就會被列印出:
在這裡插入圖片描述

六、案例:資訊整理

我們有一個old.txt檔案,裡面的內容為:
小熊-蜂蜜 小狗-牛奶 小貓-小魚 小柳-陽光
現在想把它整理後放入新檔案new.txt中。整理後的內容為:
小熊:蜂蜜
小狗:牛奶
小貓:小魚
小柳:陽光
步驟如下:
1、匯入fs模組
2、使用readFile()方法,讀取old.txt的內容
3、判斷檔案是否讀取成功
4、讀取成功後,處理內容
5、處理完成後,使用writeFile()方法,將內容寫入到新檔案new.txt中
程式碼如下:

//匯入fs模組
const fs = require('fs');
//使用readFile()方法,讀取old.txt裡的內容
fs.readFile('./old.txt','utf8',function (err,result){
    if(err){
        console.log('讀取失敗:',err)
    }else{
        //處理讀取到的資料
        //先從空格處分隔字串,使它成為陣列
        const newtxt = result.split(' ');
        //遍歷陣列,且將每個資料中的-替換為:
        const as = [];
        for(let k of newtxt){
            const b = k.replace('-',':');
            as.push(b)
        }
        //將替換後的陣列轉換為字串,且每一項之間換行
        const str = as.join('\n');
        //將處理好的檔案通過writeFile()方法寫入new.txt中
        fs.writeFile('./new.txt',str,function (err){
            if(err){
                return console.log('寫入失敗')
            }else{
                console.log('寫入成功')
            }
        })
    }

在這裡插入圖片描述
在這裡插入圖片描述

七、fs模組-路徑動態拼接的問題

在使用fs模組操作檔案時,如果提供的操作路徑是以./或…/開頭的相對路徑時,很容易出現路徑動態拼接錯誤的問題,原因是程式碼在執行的時候,會以執行node命令時所處的目錄,動態拼接出被操作檔案的完整路徑。
解決方案1:在使用fs模組操作檔案時,直接提供完整的路徑,不要提供./或…/開頭的相對路徑,從而防止路徑動態拼接的問題。
注意:在js中,一個\的意思是跳脫,連個\才代表斜線的意思,所以完整路徑要寫為:

C:\\Users\\ace23\\Documents

這種方法的缺點是移植性差,且不利於維護,路徑較長時,一處寫錯會很麻煩
解決方案2:__dirname+’路徑’:__dirname表示當前檔案所處的目錄
如:

const fs = require('fs');
fs.readFile(__dirname+'/fs1.txt','utf8',function (err,result){
    if(err){
        console.log('讀取失敗:'+err.message)
    }else{
        console.log('讀取成功')
        console.log(result)
    }
})

在這裡插入圖片描述

八、開啟一個檔案

在非同步模式下開啟檔案的語法是:

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

path - 檔名,包括路徑字串。
flags - 標誌要開啟的檔案的方式,預設值: ‘r’。flags引數的常用取值:
–‘r’:以唯讀方式開啟檔案,若檔案不存在則報異常
–‘w’:開啟檔案進行寫入,若檔案不存在則建立檔案
–‘a’:向檔案中追加內容,若檔案不存在則建立檔案
–‘rs’:同步方式開啟檔案
mode - 設定檔案模式,但前提是已建立該檔案。它預設為0666,可讀取和寫入。
callback - 這是回撥函數,有兩個引數(err, fd)。
舉例如下:

//開啟檔案
const fs = require('fs');
fs.open(__dirname+'/fs1.txt',function (err,fd){
   		fs.readFile('./fs1.txt','utf8',function (err,data){
       		console.log(data)
   		})
   		console.log('開啟檔案成功');
   		console.log(fd);
});

結果如下:
在這裡插入圖片描述

九、獲取檔案資訊

它產生一個物件,該物件包含了該檔案或目錄的具體資訊。通過該方法,判斷正在處理的是一個檔案,還是一個目錄。語法格式如下:

fs.stat(path[, options], callback);

引數的說明:
path - 檔名,包括路徑字串。
options - bigint 返回的 <fs.Stats> 物件中的數值是否應為 bigint。預設值: false。
callback - 回撥函數得到兩個引數(err, stats) 。其中stats 是 <fs.Stats> 物件,表示檔案的狀態資訊。
我們還可以通過stats的isFile()與isDirectory()方法判斷檔案是否為檔案格式或者資料夾格式。
舉例如下:

//獲取檔案資訊
const fs = require('fs');
fs.stat('./fs1.txt',function (err,stats){
   		if(err){
       		return console.log(err);
   		}
   		console.log(stats);
   		console.log(stats.isFile());
});

結果如下:
在這裡插入圖片描述

十、建立目錄

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

引數說明:
path - 包括路徑的目錄名。
mode - 要設定的目錄許可權,預設是可讀可寫。
callback - 回撥函數
舉例如下:

//建立目錄
const fs = require('fs');
fs.mkdir('./study',function (err){
  		 if(err){
       		return console.log(err);
   		}
   		console.log('目錄建立成功');
});

十一、刪除目錄

fs.rmdir(path, callback);

引數說明:
path - 包括路徑的目錄名。
callback - 回撥函數
舉例如下:

//刪除目錄
const fs = require('fs');
fs.rmdir('./study',function (err){
   		if(err){
       		return console.log(err);
   		}
   		console.log('目錄刪除成功');
});

十二、讀取目錄

fs.readdir(path, callback);

引數說明:
path - 包括路徑的目錄名。
callback - 回撥函數,兩個引數(err, files),其中檔案的檔名的目錄中的陣列排除 ‘.’ 和 ‘…’,'files’是列表,當中放的是當前目錄下的檔案或資料夾名稱。
舉例如下:

//讀取目錄
const fs = require('fs');
fs.readdir('./',function (err,file){
    if(err){
        return console.log(err);
    }
    console.log(file);
})

結果如下:
在這裡插入圖片描述