03菱涤、NodeJS-文件操作

一绰精、核心模塊和對象

  • 核心模塊的意義
  - 如果只是在服務器運行JavaScript代碼察绷,意義并不大洲胖,因為無法實現(xiàn)任何功能(讀寫文件,訪問網(wǎng)絡)鹊杖。
  - Node 的用處在于它本身還提供的一系列功能模塊悴灵,用于與操作系統(tǒng)互動。
  - 這些核心的功能模塊在 Node 中內(nèi)置骂蓖。
  • 常用內(nèi)置模塊
    • path:處理文件路徑
    • fs:操作文件系統(tǒng)
    • child_process:新建子進程
    • util:提供一系列實用小工具
    • http:提供HTTP服務器功能
    • url:用于解析URL
    • querystring:解析URL中的查詢字符串
    • crypto:提供加密和解密功能
    • 其他

二积瞒、文件系統(tǒng)操作

  • 相關模塊的使用
  - fs: 基礎的文件操作 API
  - path: 提供和路徑相關的操作 API
  - readline: 用于讀取大文本文件,一行一行讀
  - fs-extra(第三方文件操作模塊): https://www.npmjs.com/package/fs-extra 
  • path模塊的使用
    在文件操作的過程中登下,都必須使用物理路徑(絕對路徑)茫孔,path模塊提供了一系列與路徑相關的 API;
  // path.basename(path[, ext])
  // 獲取文件名(包含后綴)
  console.log(path.basename(temp));
  // 獲取文件名(不包含后綴) 第二個參數(shù)即要刪除的后綴
  console.log(path.basename(temp, '.lrc'));
  
  // path.delimiter
  // 獲取不同操作系統(tǒng)中默認的路徑分隔符
  // windows是分號,Linux是冒號
  console.log(path.delimiter);
  // 獲取環(huán)境變量
  console.log(process.env.PATH); 
  // 將對應環(huán)境變量分割
  console.log(process.env.PATH.split(path.delimiter));

  // path.dirname(path)
  // 獲取目錄名稱
  console.log(path.dirname(temp));

  // path.extname(path)
  // 獲取后綴名被芳,包含點(在path.basename中就有ext)
  console.log(path.extname(temp));

  // path.parse(path)
  // 將路徑字符串轉(zhuǎn)為對象(文件根目錄缰贝、文件路徑、文件全名(帶后綴)畔濒、后綴名剩晴、文件名(不帶后綴))
  console.log(path.parse(temp));

  // path.format(pathObject)
  // 路徑對象轉(zhuǎn)字符串
  console.log(path.format( path.parse(temp) ));

  // path.isAbsolute(path)
  // 判斷是否為絕對路徑
  console.log(path.isAbsolute(temp));

  // path.join([...paths])
  // 路徑拼接
  const temp = path.join(__dirname, './lyrics/相依為命.lrc');

  // path.normalize(path)
  // 常規(guī)化一個路徑(將多余的斜杠處理,)
  var urlStr = 'C:/System32\\a//test///haha.html';
  console.log(path.normalize(urlStr));

  // path.relative(from, to)
  // 獲取to相對于from的相對路徑
  console.log(path.relative(__dirname, '/Users/test/Desktop/03-文件系統(tǒng)操作/haha.html'));

  // path.resolve([...paths])
  // 類似于join的字符串拼接
  console.log(path.resolve(__dirname, '../', '../', 'haah.html'));
  // 與join不一樣的(不是簡單的字符串拼接)
  console.log(path.resolve(__dirname, '/User/test', 'hehe', 'haha.html'));  // 輸出結果是/User/test/hehe/haha.html
  • 同步或異步調(diào)用
  - fs模塊對文件的幾乎所有操作都有同步和異步兩種形式
  - 例如:readFile() 和 readFileSync()
  - 同步調(diào)用會阻塞代碼的執(zhí)行侵状,異步則不會
  - 異步調(diào)用會將讀取任務下達到任務隊列赞弥,直到任務執(zhí)行完成才會回調(diào)
  - 異常處理方面,同步必須使用 try catch 方式趣兄,異步可以通過回調(diào)函數(shù)的第一個參數(shù)
  • 文件讀取
    • 異步文件讀取
      fs.readFile(file[, options], callback(error, data))
// 讀取時有設置編碼utf8
fs.readFile(path.join(__dirname, './test.txt'), 'utf8', (error, data)=>{
      if(error) throw error;
      console.log(`異步: ${data}`);
});
  • 同步文件讀取
    fs.readFileSync(file[, options])
// 同步操作的寫法绽左,錯誤是通過拋出異常
try {
      var data = fs.readFileSync(path.join(__dirname, './test.txt'), 'utf8');
      console.log(`同步: ${data}`);
} catch (error) {
      throw  error;
}

node默認編碼類型是utf8;
由于Windows平臺下默認文件編碼是GBK艇潭,在node中是不支持的gbk類型編碼的!!!!
對于各種操作系統(tǒng)中編碼問題,可以通過iconv-lite解決

  • 文件流的方式讀取
    fs.createReadStream(path[, options])
const stream = fs.createReadStream('1.txt');
let data = ' '
stream.on('data', (trunk) => {
    data += trunk;
});
stream.on('end', () => {
    console.log(data);
});

流的方式Stream模塊拼窥。pipe管道,可以將讀取到流蹋凝,導入到另外一個目標中鲁纠,還可以設置流的類型;
fs.createReadStream(filename)假如該文件流數(shù)據(jù)類型是utf8 通過pipe仙粱,將流的類型改變gbk fs.createReadStream(filename).pipe(iconv.decodeStream('gbk'))

  • 模塊逐行讀取文本
    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);
  });

正則表達式: objReg.exec(string) 該函數(shù)通過對指定你的字符串進行一次匹配檢測房交,獲取字符串中的第一個與正則表達式的內(nèi)容,并且將匹配的內(nèi)容和子匹配的結果存放在返回數(shù)組中
var rel = /^\[\d{2}\:\d{2}\.\d{2,4}\].+$/;
var rel = /^\[(\d{2})\:(\d{2})\.(\d{2,4})\](.+)$/; // 有括號的即為子分組
rel.exec(line)

> 案例: 歌詞滾動

案例: 根據(jù)歌曲時間顯示對應歌詞

  • 文件寫入
    • 異步文件寫入
      fs.writeFile(file,data[,option],callback(err))
  fs.writeFile(path.join(__dirname, './temp.txt'), JSON.stringify({id: 10}), (err) => {
    if(err){
        // 一般寫文件伐割,如果出現(xiàn)錯誤候味,都是因為權限問題(權限不夠不能創(chuàng)建文件)
        // 文件夾如果不存在刃唤,不會創(chuàng)建文件夾,也會出錯
        console.log('err:' + err);
    } else {
        console.log('文件寫入成功');
    }
});
  • 同步文件寫入
    fs.writeFileSync(file,data,[,option])
  fs.writeFileSync(path.join(__dirname, 'temp.txt'), '你好?');
  • 流式文件寫
    fs.createWriteStream(path[,option])
fs.createWriteStream();
var streamWriter = fs.createWriteStream(path.join(__dirname, 'temp.txt'));
  // 是屬于非阻塞的streamWriter.write白群,返回true/false
 console.log( streamWriter.write('哈哈', ()=>{
      console.log('+1');
}) );

默認寫入操作是覆蓋源文件

  • pipe管道方式(文件讀寫操作)
var readstream = fs.createReadStream('01-path.js');
var writestream = fs.createWriteStream('test4.txt');
// 直接將讀文件流 導入到 寫文件流中
readstream.pipe(writestream);
  • 異步追加
    fs.appendFile(file,data[,options],callback(err))
fs.appendFile(path.join(__dirname, 'temp.txt'), ' 測試', (err)=>{
    if(err){
        console.log('error: ' + err);
    } else {
        console.log('追加成功');
    }
});
  • 同步追加
    fs.appendFileSync(file,data[,options])
fs.appendFileSync(path.join(__dirname, 'temp.txt'), ' 追加成功了嗎?');
  • 文件其他操作
    • 獲取文件信息
      fs.stat(path,callback(err,stats))
      fs.statSync(path) // => 返回一個fs.Stats實例
fs.stat('temp.txt', (err, stats)=>{
    if(err){
        console.log('err:' + err);
    } else {
        console.log(stats.isFile());
    }
});

讀取到文件信息后尚胞,可以判斷文件的類型
stats.isFile()
stats.isDirectory()

stats.isBlockDevice()
stats.isCharacterDevice()
stats.isSymbolicLink()
stats.isSocket()

  • 移動文件、重命名文件或目錄
    fs.rename(oldPath,newPath,callback)
    fs.renameSync(oldPath,newPath)
  fs.rename('temp.txt', 'test.txt', (err)=>{
    if(err){
        console.log('err:' + err);
    } else {
        console.log('修改文件名成功');
    }
});
  • 刪除文件
    fs.unlink(path,callback(err))
    fs.unlinkSync(path)
fs.unlink('test.txt', (err)=>{
    if(err){
        console.log('err:' + err);
    } else {
        console.log('刪除文件名成功');
    }
});
  • 目錄操作
    • 創(chuàng)建一個目錄
      fs.mkdir(path[,model],callback)
      fs.mkdirSync(path[,model])
fs.mkdir(path.join(__dirname, 'test.txt'), (err)=>{
    if(err){
        console.log(err);
    } else {
        console.log('創(chuàng)建文件成功');
    }
});
  • 刪除一個空目錄
    fs.rmdir(path,callback)
    fs.rmdirSync(path)
fs.rmdir(path.join(__dirname, 'test.txt'), (err)=>{
         if(err){
            console.log('err:' + err);
         }else{
             console.log('刪除成功');
         }
 });
  • 讀取一個目錄
    fs.readdir(path,callback(err,files))
    fs.readdirSync(path) // => 返回files
fs.readdir(__dirname, (err, files)=>{
           if(err){
            console.log('err:' + err);
           }else{
             console.log(files);
           }
});

三帜慢、緩沖區(qū)

  • 什么是緩沖區(qū)
  - 緩沖區(qū)就是內(nèi)存中操作數(shù)據(jù)的容器  
  - 只是數(shù)據(jù)容器而已
  - 通過緩沖區(qū)可以很方便的操作二進制數(shù)據(jù)
  - 而且在大文件操作時必須有緩沖區(qū)
  • 為什么要有緩沖區(qū)
    JavaScript是比較擅長處理字符串笼裳,但是早期的應用場景主要用于處理HTML文檔,不會有太大篇幅的數(shù)據(jù)處理粱玲,也不會接觸到二進制的數(shù)據(jù)躬柬。而在Node中操作數(shù)據(jù)、網(wǎng)絡通信是沒辦法完全以字符串的方式操作的抽减,所以在Node中引入了一個二進制的緩沖區(qū)的概念:Buffer允青。

  • 緩沖區(qū)簡單操作

  // 創(chuàng)建長度為4個字節(jié)的緩沖區(qū)
  var buffer = new Buffer(4);

  // 通過指定編碼的方式創(chuàng)建
  var buffer = new Buffer('hello', 'utf8');

  // 往緩沖區(qū)中寫數(shù)據(jù)(假如緩沖區(qū)只有4個字節(jié)大小)
  buffer.write('123456');
  console.log(buffer.toString('utf8'));  // 輸出是1234

node中默認的編碼類型都是utf-8;

  • 讀圖片操作
  var fs = require('fs');
  var path = require('path');

  fs.readFile(path.join(__dirname, './test.png'), (error, data)=>{
      if(error) console.error(error);
      // 將buffer內(nèi)容讀取出來(圖片是base64)
      console.log(data.toString('base64'));
  });

還原生成Base64編碼為圖片: http://www.atool.org/img2base64.php;
注意: 要在前面添加上data:image/png;base64,表示圖片類型;

  • node支持的編碼
    Buffers 和 JavaScript 字符串對象之間轉(zhuǎn)換時需要一個明確的編碼方法卵沉。
  - 'ascii' - 7位的 ASCII 數(shù)據(jù)颠锉。這種編碼方式非常快史汗,它會移除最高位內(nèi)容
  - 'utf8' - 多字節(jié)編碼 Unicode 字符琼掠。大部分網(wǎng)頁和文檔使用這類編碼方式
  - 'utf16le' - 2個或4個字節(jié), Little Endian (LE) 編碼 Unicode 字符。編碼范圍 (U+10000 到 U+10FFFF) 
  - 'ucs2' - 'utf16le'的子集
  - 'base64' - Base64 字符編碼
  - 'binary' - 僅使用每個字符的頭8位將原始的二進制信息進行編碼
(在需使用 Buffer 的情況下停撞,應該盡量避免使用這個已經(jīng)過時的編碼方式瓷蛙,這個編碼方式將會在未來某個版本中棄用)。
  - 'hex' - 每個字節(jié)都采用 2 進制編碼戈毒。

在node中是不支持的gbk類型編碼的!!!!
對于各種操作系統(tǒng)中編碼問題速挑,可以使用第三方模塊iconv-lite

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市副硅,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌翅萤,老刑警劉巖恐疲,帶你破解...
    沈念sama閱讀 216,402評論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異套么,居然都是意外死亡培己,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評論 3 392
  • 文/潘曉璐 我一進店門胚泌,熙熙樓的掌柜王于貴愁眉苦臉地迎上來省咨,“玉大人,你說我怎么就攤上這事玷室×闳兀” “怎么了笤受?”我有些...
    開封第一講書人閱讀 162,483評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長敌蜂。 經(jīng)常有香客問我箩兽,道長,這世上最難降的妖魔是什么章喉? 我笑而不...
    開封第一講書人閱讀 58,165評論 1 292
  • 正文 為了忘掉前任辑舷,我火速辦了婚禮滔灶,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己慨蛙,他們只是感情好,可當我...
    茶點故事閱讀 67,176評論 6 388
  • 文/花漫 我一把揭開白布左医。 她就那樣靜靜地躺著狐胎,像睡著了一般。 火紅的嫁衣襯著肌膚如雪遏片。 梳的紋絲不亂的頭發(fā)上嘹害,一...
    開封第一講書人閱讀 51,146評論 1 297
  • 那天,我揣著相機與錄音吮便,去河邊找鬼笔呀。 笑死,一個胖子當著我的面吹牛髓需,可吹牛的內(nèi)容都是我干的许师。 我是一名探鬼主播,決...
    沈念sama閱讀 40,032評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼僚匆,長吁一口氣:“原來是場噩夢啊……” “哼微渠!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起咧擂,我...
    開封第一講書人閱讀 38,896評論 0 274
  • 序言:老撾萬榮一對情侶失蹤逞盆,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后松申,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體云芦,經(jīng)...
    沈念sama閱讀 45,311評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,536評論 2 332
  • 正文 我和宋清朗相戀三年贸桶,在試婚紗的時候發(fā)現(xiàn)自己被綠了舅逸。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,696評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡皇筛,死狀恐怖琉历,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤旗笔,帶...
    沈念sama閱讀 35,413評論 5 343
  • 正文 年R本政府宣布彪置,位于F島的核電站,受9級特大地震影響换团,放射性物質(zhì)發(fā)生泄漏悉稠。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,008評論 3 325
  • 文/蒙蒙 一艘包、第九天 我趴在偏房一處隱蔽的房頂上張望的猛。 院中可真熱鬧,春花似錦想虎、人聲如沸卦尊。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽岂却。三九已至,卻和暖如春裙椭,著一層夾襖步出監(jiān)牢的瞬間躏哩,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評論 1 269
  • 我被黑心中介騙來泰國打工揉燃, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留扫尺,地道東北人。 一個月前我還...
    沈念sama閱讀 47,698評論 2 368
  • 正文 我出身青樓炊汤,卻偏偏與公主長得像正驻,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子抢腐,可洞房花燭夜當晚...
    茶點故事閱讀 44,592評論 2 353

推薦閱讀更多精彩內(nèi)容