fs是filesystem的縮寫,基本上就是node對(duì)于文件系統(tǒng)操作封裝的一些api
一、文件的讀寫
文件的讀寫這里面的api有readFile(),writeFile(),和readFileSync(),writeFileSync()。前者是異步,后者是同步,兩種不同的情況供開(kāi)發(fā)者選擇。
readFile()和readFileSync()
readFile用于異步讀取數(shù)據(jù),他有幾個(gè)參數(shù):
| 參數(shù) | 是否必須 | 例子 | 作用 |
|---|---|---|---|
| 文件的路徑 | 是 | './image.png' | 可以是絕對(duì)路徑,也可是相對(duì)路徑,如果是相對(duì)路徑,是相對(duì)于當(dāng)前進(jìn)程所在的路徑 process.cwd(),官方文檔上好像寫也可以傳一個(gè)buffer......還能是文件名和文件描述符(不知道是什么東西) |
| options配置 | 否 | 'utf-8' | 可以配置文件編碼實(shí)例,默認(rèn)是utf-8 |
| 讀取完成后的回調(diào)參數(shù) | 是 | func (err, buffer) { } | 該函數(shù)一參是發(fā)生錯(cuò)誤時(shí)的錯(cuò)誤對(duì)象,二參是代表文件內(nèi)容的buffer實(shí)例 |
如果,文件的路徑是一個(gè)目錄,會(huì)返回一個(gè)錯(cuò)誤......freeBSD不會(huì),好像基于平臺(tái).....
同步的方法readFileSync()和這個(gè)一樣,使用的例子如下
const text = fs.readFile('etc/passws', 'utf-8' (error, buffer) => {
if(error) throw err
console.log(buffer)
}) {
}
//將文件按行拆成數(shù)組......
text.split(/\r?\n/).forEach((item) => {
console.log(item)
})
writeFile()和writeFileSync()
用于寫入文件。
| 參數(shù) | 是否必須 | 例子 | 作用 |
|---|---|---|---|
| 文件路徑 | 是 | 上同 | 上同 |
| 寫入的字符串或文件 | 是 | 'hello’ | 可以是字符串,也可以是文件名,還可以是buffer |
| option配置 | 否 | 上同 | 上同 |
| 寫入完成時(shí)的回調(diào) | 是 | 上同 | 上同 |
fs.writeFile('message.txt', 'Hello Node.js', (err) => {
if (err) throw err;
console.log('The file has been saved!');
});
這里的官方文檔上寫了注意......多次對(duì)同一文件使用,而且不等待回調(diào)函數(shù),是不安全的,對(duì)于多次寫入同一文件,強(qiáng)烈建議使用fs.createWriteStream
fs.createWriteStream()
這個(gè)方法,創(chuàng)建了一個(gè)寫入數(shù)據(jù)流的對(duì)象,該對(duì)象的write方法用于寫入數(shù)據(jù),end方法用于結(jié)束寫入操作.....
const out = fs.createWriteStream(fileName, {
flags: 'w',
encoding: 'utf8',
fd: null,
mode: 0o666,
autoClose: true
})
out.write(str)
out.end()
| 參數(shù) | 是否必須 | 作用 |
|---|---|---|
| 文件路徑 | 是 | 略 |
| options | 是 | 一些配置,具體的配置有flags:一個(gè)string,大概是寫入的模式比如w,r+等,encoding:編碼;fd;mode;autoClose:設(shè)置是否自動(dòng)關(guān)閉;start:一個(gè)integer |
注意: 如果autoClose設(shè)置為true(默認(rèn)),則在遇到error和end的時(shí)候,會(huì)自動(dòng)關(guān)閉,如果是false,即使有錯(cuò)誤,也不會(huì)被關(guān)閉,所以要注意了,你要正確的負(fù)責(zé)關(guān)閉。,并確保文件描述符沒(méi)有泄露, fd和mode暫時(shí)還不知道它的作用。
如果要對(duì)統(tǒng)一文件進(jìn)行反復(fù)的讀寫,知道一直不停的out.write()就可以了,最后別忘記end()
相對(duì)的createWriteStream和它一樣使用,但是它會(huì)返回一個(gè)ReadStream可讀流對(duì)象。而且它第二個(gè)參數(shù)options中對(duì)了一個(gè)end字段。
fs.createReadStream('sample.txt', { start: 90, end: 99 });
// 設(shè)置了start和end之后,使其可以從文件讀取一定范圍的字節(jié)而不是整個(gè)文件
createWriteStream和createReadSteam結(jié)合使用拷貝大文件實(shí)例
const fileCopy = (filename1, filename2, done) => {
let input = fs.createReadStream(filename1);
let output = fs.createWriteStream(filename2);
input.on('data', function(d) { output.write(d) })
input.on('error', function(error) { throw error })
input.on('end', function() {
output.end()
if (done) done();
})
}
二、文件的操作
exist() 、mkdir()
exist()判斷文件目錄是否存在,他的回調(diào)函數(shù)參數(shù),是不管最后結(jié)果如何都會(huì)調(diào)用的,需要注意的是,以前我們寫java的文件IO,在打開(kāi)文件的時(shí)候都需要先用類似方法判斷目錄是否存在,但是node里邊,open方法本身就能檢查,
mkdir()用于新建目錄,它接收三個(gè)參數(shù),目錄名、權(quán)限值和回調(diào)函數(shù)
const fs = require('fs');
// 如果給定目錄存在,就刪除它。
if(fs.existSync(outputFolder)) {
console.log('刪除' + outputFolder)
fs.rmdirSync(outputFolder)
}
// 新建目錄
fs.mkdir('./helloDir',0777, function (err) {
if (err) throw err;
});
stat()
它用來(lái)判斷是一個(gè)文件還是一個(gè)目錄,接收一個(gè)文件或者目錄。
watch()
| 參數(shù) | 是否必須 | 作用 |
|---|---|---|
| 文件名 | 是 | 略 |
| options參數(shù) | fou | 如果指定,則是一個(gè)對(duì)象,包括persistet:布爾值(默認(rèn)true),表明文件被監(jiān)控時(shí),進(jìn)程是否還要繼續(xù)運(yùn)行; recursive:指明是否全部子目錄應(yīng)該被監(jiān)視,或只是當(dāng)前目錄(默認(rèn)false);encoding:默認(rèn)utf-8 |
監(jiān)控文件,如果文件發(fā)生變化,則觸發(fā)回調(diào)函數(shù)。返回的是一個(gè)fs.FSWatch
| 參數(shù) | 是否必須 | 作用 |
|---|---|---|
| 文件名 | 是 | 略 |
| options參數(shù) | fou | 如果指定,則是一個(gè)對(duì)象,包括persistet:布爾值(默認(rèn)true),表明文件被監(jiān)控時(shí),進(jìn)程是否還要繼續(xù)運(yùn)行; recursive:指明是否全部子目錄應(yīng)該被監(jiān)視,或只是當(dāng)前目錄(默認(rèn)false);encoding:默認(rèn)utf-8 |
fs.watch('somedir', (eventType, filename) => {
console.log(`事件類型是: ${eventType}`);
if (filename) {
console.log(`提供的文件名: ${filename}`);
} else {
console.log('未提供文件名');
}
});
注意,還有一個(gè)watchFile(),作用和它差不多,效率低,官方建議用這個(gè)。但fs.watch API 不是 100% 跨平臺(tái)一致的,且在某些情況下不可用。遞歸選項(xiàng)只支持 macOS 和 Windows
fs.lstat(path)
接收一個(gè)文件url,返回一個(gè)fs.Stats實(shí)例,他的同步方法是fs.lstatSync(path)
三、webpack應(yīng)用,寫一個(gè)多入口的初始化entry函數(shù)
在使用開(kāi)發(fā)react應(yīng)用的時(shí)候,使用webpack打包需要有多入口的時(shí)候,也就是說(shuō),我有多個(gè)entry,每個(gè)enrty各自生成一個(gè)html模版,這個(gè)時(shí)候,我們可以寫個(gè)自動(dòng)腳本,如下
const _ = require('lodash')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const fs = require('fs');
const path = require('path');
const entryDir = path.join(__dirname, 'src/entry/')
const templateFile = path.join(__dirname, 'index.html')
const addEntryFn = (config, key, value) => {
console.log(`找到了entry!,key=${key},value=${value}`);
config.entry[key] = value
config.plugins.push(new HtmlWebpackPlugin(
{
title: key,
filename: key + '.html',
chunks: [key],
template: templateFile,
multihtmlCache: true,
}
))
}
const getEntrys = (config, rootpath, fn) => {
const files = fs.readdirSync(rootpath)
for(let key in files) {
const fullName = path.join(rootpath, "/", files[key])
const stat = fs.lstatSync(fullName)
if (stat.isDirectory()) {
getEntrys(config, fullName, fn)
} else {
const fileName = path.basename(fullName, '.jsx')
if (_.startsWith(fileName, 'entry-')) {
const entryKey = fileName.replace('entry-', '')
fn(config, entryKey, fullName)
}
}
}
}
module.exports = function (config) {
getEntrys(config, entryDir, addEntryFn);
}