文件編碼問題
1、node
在讀取文件的時候是不支持讀取GBK
編碼的文件,一般都是utf8
,所以有的時候我們需要讀取GBK
文件時,可以借助第三方插件iconv-lite
來轉(zhuǎn)換成我們所需要的編碼形式。
- 1、https://www.npmjs.com/package/iconv-lite 首先去官網(wǎng)下載
iconv-lite
這個模塊,然后用require
引入該模塊。只要是文件操作,都要引用fs
和path
兩個模塊
/**
* Created by 黃森 on 2017/6/7.
*/
const fs = require('fs');
const path = require('path');
const iconv = require('iconv-lite');
fs.readFile(path.join(__dirname,'./血染的風(fēng)采.lrc'),(error,data)=>{
//decode中兩個參數(shù),第一個為你要轉(zhuǎn)化的buffer,第二個為你要轉(zhuǎn)化的編碼方式
console.log(iconv.decode(data,'GBK'));
// console.log(data.toString('GBK'));
});
這樣就可以將我們所讀取的buffer轉(zhuǎn)化成GBK
格式的文件,如果直接使用data.toString('GBK')
的話會提示這樣的錯誤:
buffer.js:480
throw new TypeError('Unknown encoding: ' + encoding);
^
TypeError: Unknown encoding: gbk
at Buffer.slowToString (buffer.js:480:17)
at Buffer.toString (buffer.js:493:27)
at fs.readFile (F:\WebstormProjects\untitled\06.js:10:22)
at FSReqWrap.readFileAfterClose [as oncomplete] (fs.js:446:3)
小小案例(動態(tài)顯示歌詞)
將lrc
的歌詞按照時間順序?qū)?yīng)的歌詞在控制臺顯示
/**
* Created by 黃森 on 2017/6/7.
*/
// 動態(tài)顯示歌詞
//引入模塊
const fs = require('fs');
const path = require('path');
const iconv = require('iconv-lite');
fs.readFile(path.join(__dirname,'./血染的風(fēng)采.lrc'),(error,data)=>{
//按照換行分割歌詞
var lines = iconv.decode(data, 'gbk').split('\n');
// console.log(lines.length);
//正則匹配歌詞
var regex = /\[(\d{2})\:(\d{2})\.(\d{2})\]\s(.+)/;
//計時間差
var begin = new Date().getTime();
// 遍歷
lines.forEach((line) => {
// [00:32.67] 也許我告別 將不再回來
var matches = regex.exec(line);
if (matches) {
var m = parseFloat(matches[1]);
var s = parseFloat(matches[2]);
var f = parseFloat(matches[3]);
var lyric = matches[4]; // 當(dāng)前行歌詞不是立即執(zhí)行
// 由于下達(dá)輸出任務(wù)的時刻不同
// 由于代碼執(zhí)行需要消耗時間,所以要減去執(zhí)行時間
var offset = new Date().getTime() - begin;
setTimeout(() => {
console.log(lyric);
}, m * 60 * 1000 + s * 1000 + f - offset);
} else {
// 不是一行歌詞
console.log(line);
}
});
});
但是這種方式是一下把所有的內(nèi)容全部讀取到內(nèi)存中,文件比較大的話就會出現(xiàn)卡頓,node
就提供了一個讀取單行文本的api
2、readline模塊逐行讀取文本
下面用readline
模塊改版讀取歌詞
/**
* Created by 黃森 on 2017/6/7.
*/
// readline動態(tài)顯示歌詞
const fs = require('fs');
const path = require('path');
const iconv = require('iconv-lite');
const readline = require('readline');
var filename = path.join(__dirname, './../lyrics/血染的風(fēng)采.lrc');
var streamReader = fs.createReadStream(filename)
.pipe(iconv.decodeStream('gbk'));
// 利用readline讀取
var rl = readline.createInterface({ input: streamReader });
var begin = new Date().getTime();
rl.on('line', (line) => {
task(line, begin);
});
var regex = /\[(\d{2})\:(\d{2})\.(\d{2})\]\s(.+)/;
//輸出歌詞,抽出單獨(dú)方法
function task(line, begin) {
// [00:32.67] 也許我告別 將不再回來
var matches = regex.exec(line);
if (matches) {
var m = parseFloat(matches[1]);
var s = parseFloat(matches[2]);
var f = parseFloat(matches[3]);
var lyric = matches[4]; // 當(dāng)前行歌詞不是立即執(zhí)行
// 由于下達(dá)輸出任務(wù)的時刻不同
var offset = new Date().getTime() - begin;
setTimeout(() => {
console.log(lyric);
}, m * 60 * 1000 + s * 1000 + f - offset);
} else {
// 不是一行歌詞
console.log(line);
}
}
3、文件寫入
異步文件寫入
fs.writeFile(file,data[,option],callback(err))
同步文件寫入
fs.writeFileSync(file,data,[,option])
流式文件寫
fs.createWriteStream(path[,option])
默認(rèn)寫入操作是覆蓋源文件
異步追加
fs.appendFile(file,data[,options],callback(err))
同步追加
fs.appendFileSync(file,data[,options])
- 1)文件異步寫入
/**
* Created by 黃森 on 2017/6/7.
*/
const fs = require('fs');
const path = require('path');
//JSON.stringify({id:10})序列化
//JSON.parse 反序列化
fs.writeFile(path.join(__dirname,'./test.txt'),JSON.stringify({id:10}),(err)=>{
if(err){
//讀文件是不存在報錯
//意外錯誤
//文件權(quán)限問題
//文件夾找不到(不會自動創(chuàng)建文件夾)
console.log('error')
}else {
console.log('success');
}
});
fs.writeFile()
方法中系一個參數(shù)為路徑,第二個參數(shù)是要寫入的內(nèi)容,第三個參數(shù)是回掉函數(shù)。JSON.stringify({id:10})
序列化,將一個對象轉(zhuǎn)化為JSON
,JSON.parse
反序列化,將JSON轉(zhuǎn)化為object
.
同步寫入fs.writeFileSync();
和異步是一樣的。
因為文件的寫入是覆蓋源文件,所以就又文件追加的這樣一個需求,node
提供了fs.appendFile()
這樣一個函數(shù),可以在原有的基礎(chǔ)上追加文件內(nèi)容。里面的參數(shù)和fs.writeFile()
是一樣的。
- 2)文件同步寫入
fs.appendFileSync(file,data[,options])
,同步寫入和異步是一樣的,參數(shù)都相同
4、其他文件操作
重命名文件或目錄/移動文件
fs.rename(oldPath,newPath,callback)
fs.renameSync(oldPath,newPath)
刪除文件
fs.unlink(path,callback(err))
fs.unlinkSync(path)
驗證路徑是否存在(過時的API,用stat代替)
fs.exists(path,callback(exists))
fs.existsSync(path) // => 返回布爾類型 exists
獲取文件信息
fs.stat(path,callback(err,stats))
fs.statSync(path) // => 返回一個fs.Stats實例
移動文件
fs.rename(oldPath,newPath)
對目錄的操作
創(chuàng)建一個目錄
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
案例:打印目錄列表
/**
* Created by 黃森 on 2017/6/7.
*/
//打印當(dāng)前目錄所有文件
const fs = require('fs');
const path = require('path');
require('./proto.js'); //格式化時間的js
//獲取當(dāng)前有沒有傳入目標(biāo)路徑
var target = path.join(__dirname,process.argv[2] || './');
fs.readdir(target,(error,files)=>{
files.forEach(files=>{
// console.log(path.join(target,files));
fs.stat(path.join(target,files),(err,stats)=>{
console.log(`${stats.mtime.format('yyyy/MM/dd HH:mm')}\t${stats.size}\t${files}`)
})
})
});
5、創(chuàng)建文件夾
/**
* Created by 黃森 on 2017/6/8.
*/
//創(chuàng)建文件夾
const fs = require('fs');
const path =require('path');
fs.mkdir(path.join(__dirname,'demo'));
文件夾路徑過長,無法拷貝問題
監(jiān)視文件變化:
fs.watchFile(filename[, options], listener(curr,prev))
options:{persistent,interval}
fs.watch(filename[,options][,listener])
利用文件監(jiān)視實現(xiàn)自動 markdown 文件轉(zhuǎn)換
https://github.com/chjj/marked
https://github.com/Browsersync/browser-sync
大文件拷貝
https://github.com/tj/node-progress
6、文件的拷貝
// 文件的復(fù)制
const fs = require('fs');
const path = require('path');
console.time('read');//計算時間
fs.readFile('C:\\Users\\iceStone\\Desktop\\1.iso', (err, data) => {
if (err) {
throw err
}
console.timeEnd('read');
console.time('write');
// 讀取完文件拿到
fs.writeFile('C:\\Users\\iceStone\\Desktop\\2.iso', data, err=> {
if (err) {
throw err
}
console.timeEnd('write');
console.log('拷貝完成');
});
});
這種方式的話,文件太大,我們電腦的內(nèi)存就會受不了,所以就會使用文件流的方式拷貝文件
// 文件流的方式的復(fù)制
const fs = require('fs');
const path = require('path');
// 創(chuàng)建文件的讀取流,并沒有讀出正式的數(shù)據(jù),開始了讀取文件的任務(wù)()
var reader = fs.createReadStream('C:\\Users\\iceStone\\Desktop\\1.itcast');
// 磁盤: 7200轉(zhuǎn) 6100轉(zhuǎn) 轉(zhuǎn)速越快 讀寫越快 資源消耗更大
fs.stat('C:\\Users\\iceStone\\Desktop\\1.itcast', (err, stats) => {
if (stats) {
var readTotal = 0;
reader.on('data', (chunk) => {
// chunk是一個buffer(字節(jié)數(shù)組)
console.log('讀了一點 進(jìn)度:' + ((readTotal += chunk.length) / stats.size * 100) + '%');
});
}
});