文件操作
相關模塊
Node內核提供了很多與文件操作相關的模塊,每個模塊都提供了一些最基本的操作API,在NPM中也有社區提供的功能包
fs:
基礎的文件操作 API
path:
提供和路徑相關的操作 API
readline:
用於讀取大文本文件,一行一行讀
fs-extra(第三方):
https://www.npmjs.com/package/fs-extra
同步或異步調用
- fs模塊對文件的幾乎所有操作都有同步和異步兩種形式
- 例如:readFile() 和 readFileSync()
- 區別:
- 同步調用會阻塞代碼的執行,異步則不會
- 異步調用會將讀取任務下達到任務隊列,直到任務執行完成才會回調
- 異常處理方面,同步必須使用 try catch 方式,異步可以通過回調函數的第一個參數
路徑模塊
在文件操作的過程中,都必須使用物理路徑(絕對路徑),path模塊提供了一系列與路徑相關的 API
console.log('join用於拼接多個路徑部分,並轉化為正常格式');
const temp = path.join(__dirname, '..', 'lyrics', './友誼之光.lrc');
console.log(temp);
console.log('獲取路徑中的文件名');
console.log(path.basename(temp));
console.log('獲取路徑中的文件名並排除擴展名');
console.log(path.basename(temp, '.lrc'));
console.log('====================================');
console.log('獲取不同操作系統的路徑分隔符');
console.log(process.platform + '的分隔符為 ' + path.delimiter);
console.log('一般用於分割環境變量');
console.log(process.env.PATH.split(path.delimiter));
console.log('====================================');
console.log('獲取一個路徑中的目錄部分');
console.log(path.dirname(temp));
console.log('====================================');
console.log('獲取一個路徑中最后的擴展名');
console.log(path.extname(temp));
console.log('====================================');
console.log('將一個路徑解析成一個對象的形式');
const pathObject = path.parse(temp);
console.log(pathObject);
console.log('====================================');
console.log('將一個路徑對象再轉換為一個字符串的形式');
// pathObject.name = '我終於失去了你';
pathObject.base = '我終於失去了你.lrc';
console.log(pathObject);
console.log(path.format(pathObject));
console.log('====================================');
console.log('獲取一個路徑是不是絕對路徑');
console.log(path.isAbsolute(temp));
console.log(path.isAbsolute('../lyrics/愛的代價.lrc'));
console.log('====================================');
console.log('將一個路徑轉換為當前系統默認的標准格式,並解析其中的./和../');
console.log(path.normalize('c:/develop/demo\\hello/../world/./a.txt'));
console.log('====================================');
console.log('獲取第二個路徑相對第一個路徑的相對路徑');
console.log(path.relative(__dirname, temp));
console.log('====================================');
console.log('以類似命令行cd命令的方式拼接路徑');
console.log(path.resolve(temp, 'c:/', './develop', '../application'));
console.log('====================================');
console.log('獲取不同平台中路徑的分隔符(默認)');
console.log(path.sep);
console.log('====================================');
console.log('允許在任意平台下以WIN32的方法調用PATH對象');
// console.log(path.win32);
console.log(path === path.win32);
console.log('====================================');
console.log('允許在任意平台下以POSIX的方法調用PATH對象');
console.log(path === path.posix);
源碼地址:
https://github.com/nodejs/node/blob/master/lib/path.js
文件讀取
Node中文件讀取的方式主要有:
fs.readFile(file[, options], callback(error, data))
fs.readFile('c:\\demo\1.txt', 'utf8', (err, data) => {
if (err) throw err;
console.log(data);
});
fs.readFileSync(file[, options])
try {
const data = fs.readFileSync('c:\\demo\1.txt', 'utf8');
console.log(data);
} catch(e) {
// 文件不存在,或者權限錯誤
throw e;
}
fs.createReadStream(path[, options])
const stream = fs.createReadStream('c:\\demo\1.txt');
let data = ''
stream.on('data', (trunk) => {
data += trunk;
});
stream.on('end', () => {
console.log(data);
});
由於Windows平台下默認文件編碼是GBK,在Node中不支持,可以通過iconv-lite解決
Readline模塊逐行讀取文本內容
const readline = require('readline');
const fs = require('fs');
const rl = readline.createInterface({
input: fs.createReadStream('sample.txt')
});
rl.on('line', (line) => {
console.log('Line from file:', line);
});
文件寫入
Node中文件寫入的方式主要有:
fs.writeFile(file, data[, options], callback(error))
fs.writeFile('c:\\demo\a.txt', new Date(), (error) => {
console.log(error);
});
fs.writeFileSync(file, data[, options])
try {
fs.writeFileSync('c:\\demo\a.txt', new Date());
} catch (error) {
// 文件夾不存在,或者權限錯誤
console.log(error);
}
fs.createWriteStream(path[,option])
var streamWriter = fs.createWriteStream('c:\\demo\a.txt');
setInterval(() => {
streamWriter.write(`${new Date}\n`, (error) => {
console.log(error);
});
}, 1000);
文件寫入
fs.appendFile(file,data[,options],callback(err))
// 相比較之前文件流的方式,這種方式不會占用文件資源,append完成就會釋放
setInterval(() => {
fs.appendFile('c:\\demo\a.txt',`${new Date}\n`, (error) => {
console.log(error);
});
}, 1000);
fs.appendFileSync(file,data[,options])
setInterval(() => {
fs.appendFileSync('c:\\demo\a.txt',`${new Date}\n`);
}, 1000);
其他常見文件操作
驗證路徑是否存在(過時的API)
- fs.exists(path,callback(exists))
- fs.existsSync(path) // => 返回布爾類型 exists
獲取文件信息
- fs.stat(path,callback(err,stats))
- fs.statSync(path) // => 返回一個fs.Stats實例
移動文件或重命名文件或目錄
與命令行相同,重命名操作也可以實現文件移動
- fs.rename(oldPath,newPath,callback)
- fs.renameSync(oldPath,newPath)
刪除文件
- fs.unlink(path,callback(err))
- fs.unlinkSync(path)
其他常見文件夾操作
創建一個目錄
- fs.mkdir(path[,model],callback)
- fs.mkdirSync(path[,model])
刪除一個空目錄
- fs.rmdir(path,callback)
- fs.rmdirSync(path)
讀取一個目錄
- fs.readdir(path,callback(err,files))
- fs.readdirSync(path) // => 返回files
文件監視
利用文件監視實現自動 markdown 文件轉換
-
相關鏈接:
-
實現思路:
- 利用
fs
模塊的文件監視功能監視指定MD文件 - 當文件發生變化后,借助
marked
包提供的markdown
tohtml
功能將改變后的MD文件轉換為HTML - 再將得到的HTML替換到模版中
- 最后利用BrowserSync模塊實現瀏覽器自動刷新
- 利用
const fs = require('fs');
const path = require('path');
var marked = require('marked');
var bs = require('browser-sync').create();
var target = path.join(__dirname, process.argv[2] || './README.md');
var filename = path.basename(target, path.extname(target)) + '.html';
var targetHtml = path.join(path.dirname(target), filename);
bs.init({
server: path.dirname(target),
index: filename,
notify: false
});
bs.reload(filename);
var template = `<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
<style>{{{styles}}}</style>
</head>
<body>
<article class="markdown">
{{{body}}}
</article>
</body>
</html>
`;
fs.readFile(path.join(__dirname, './markdown.css'), 'utf8', (error, css) => {
if (error) throw error;
template = template.replace('{{{styles}}}', css);
var handler = (current, previous) => {
fs.readFile(target, 'utf8', (error, content) => {
var html = template.replace('{{{body}}}', marked(content));
fs.writeFile(targetHtml, html, (error) => {
if (!error) {
console.log(`updated@${new Date()}`);
bs.reload(filename);
}
});
});
};
handler();
fs.watchFile(target, { interval: 100 }, handler);
});
緩沖區處理
什么是緩沖區
- 緩沖區就是內存中操作數據的容器
- 只是數據容器而已
- 通過緩沖區可以很方便的操作二進制數據
- 而且在大文件操作時必須有緩沖區
為什么要有緩沖區
- JavaScript是比較擅長處理字符串,但是早期的應用場景主要用於處理HTML文檔,不會有太大篇幅的數據處理,也不會接觸到二進制的數據。
- 而在Node中操作數據、網絡通信是沒辦法完全以字符串的方式操作的,簡單來說
- 所以在Node中引入了一個二進制的緩沖區的實現:Buffer