亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > JavaScript > 正文

詳解nodejs 文本操作模塊-fs模塊(三)

2019-11-19 18:19:18
字體:
來源:轉載
供稿:網友

下面繼續nodejs的學習,在前兩篇中,已經把文件操作的打開,關閉讀寫這兩個最基本的功能進行了簡單的說明,它們的強大之處,讓我覺得知道這幾種方法之后,基本上就可以隨意的操作文件了,但是open,read,write等方法,需要操作的參數確實是有點多的,所以,基于讓使用者更簡單的完成讀寫操作,開發者們,繼續給這些方法做了進一步的封裝,也就是本文接下來將要說的readFile,和writeFile方法,當然也有他們的同步執行方法,只是篇幅有限,并且同步的方法和異步的方法,在內部實現和參數使用中,差別不大,所以在以后的文章中,基本上不會再涉及到同步方法了。

使用方法

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

其中:

fileName是表示您要操作的文件的地址,這個地址可以使用絕對地址,也可以使用相對地址,關于它可以支持的所有規則,可以參考之前文章中的path操作,path模塊,就是專門為了地址這個功能存在的。

options是讀取文件時,所需要的參數,options是一個對象,它只包含兩個參數:options = { encoding: “utf-8”, flag: 'r' },其中,encoding表示讀取文件成功后,返回的數據的編碼格式,默認返回格式為buffer對象,flag的值表示是如何讀取文件的,支持的參數,與使用fs.open時,相同,具體請參考:文本操作模塊-fs模塊(一),但是在我個人看來,這里的flag取值一般也就是r,r+著兩種方式了,畢竟readFile就是為了讀取文件內容才定義的。

callback是回調函數,當改文件讀取成功時,執行該文件,并且callback方法支持兩個參數:

callback(err,data){  //err為讀取失敗時的錯誤對象,保持錯誤信息  //data為讀取成功時,返回的讀取信息,該信息的返回格式,是由options對象中的encoding決定 } 

在接下來給出測試用例之前,我們再來想想另外的一個問題,那就是使用fs.read方法讀取文件時,我需要知道明確的傳入要讀取信息的長度,而在這里,我要讀取一整個文件的內容,那么這個文件包含的內容的總長度要怎么計算呢?這是一個問題,當然我也是在看readFile的源碼時,看到了這個,所以才在這里提前說明一下的。

對的,fs模塊中,提供了一個方法,可以讓你獲取到文件的一些基本信息,這個方法就是fs.fstat方法,它也是一個異步執行的方法,使用方法如下:

var fs = require("fs");  fs.open('fs.js','r',function(err,fd){  if(err){   console.log("open file error");   //如果打開文件失敗時,會執行到這里   return false;  }   fs.fstat(fd,function(err,state){   if(err){    console.log("err when fstate!");    return false;   }    console.log(state);   //state是一個對象,其中包含著當前打開文件的一些基本信息  }); }); 

保持上面的代碼,然后在控制臺執行的結果如下:

{  dev: 16777220,  mode: 33279,  nlink: 1,  uid: 501,  gid: 20,  rdev: 0,  blksize: 4096,  ino: 1456286,  size: 86418,  blocks: 176,  atime: Sat Aug 15 2015 15:46:59 GMT+0800 (CST),  mtime: Sat Aug 15 2015 15:01:55 GMT+0800 (CST),  ctime: Sat Aug 15 2015 15:01:55 GMT+0800 (CST),  birthtime: Mon Aug 03 2015 22:47:02 GMT+0800 (CST) } 

當我們使用console.log在控制臺打印信息時,只能顯示一些本身的屬性,其實state還支持一些方法,比如:isDirectory,isFile,isBlockDevice等方法,這里因為我平時也不會太用到nodejs做東西,所以對其中的很多屬性,都用不到,使用不到,所以也就導致,我對于這個屬性或者方法的含義,不能很好的理解,所以這里就不多說了。

至于關于state的東西,可以在fs.js中,查看查找fs.State構造函數,既可以找到所有包含的信息。

測試用例

var fs = require("fs");  fs.readFile('test.js',"utf-8",function(err,data){  if(err){   console.log("readFile file error");   return false;  }   console.log(data); }); 

上面給出的是最簡單的示例了,因為我讀取的文件中,保持的內容只是一段中文文本,所以這里使用的是utf-8的編碼格式,如果這里不傳入編碼格式,那么返回的data值則是一個Buffer對象。

readFile源碼分析

雖然這里叫做源碼分析,實質上,只是來一起看下,readFile在源碼中是如何實現的。該部分只有源碼,請查看源碼中對應的注釋,了解源碼的整改結構。

fs.readFile = function(path, options, callback_) {  var callback = maybeCallback(arguments[arguments.length - 1]);  //msybeCallback用來判斷是否為一個function,這里時判斷傳入的第二個參數是否為function  //如果不是,那么就定義一個,這里對于后面的邏輯影響不大   //給options設置一些默認值,readFile的第二個參數,只能是三種情況  //1:function,這個時候,options使用默認值,第二個參數為回調函數  //2:string類型,這個時候,第二個參數為encoding的屬性值  //3:object類型,這個時候,表示options為一個完整的對象,可能包含也可能不包含encoding和flag屬性  //如果不為上述的三種類型,那么直接拋出一個類型異常,停止執行  if (util.isFunction(options) || !options) {   options = { encoding: null, flag: 'r' };  } else if (util.isString(options)) {   options = { encoding: options, flag: 'r' };  } else if (!util.isObject(options)) {   throw new TypeError('Bad arguments');  }   var encoding = options.encoding;  assertEncoding(encoding);  //判斷encoding是否為當前支持的編碼類型,如果不支持,則拋出一個異常,停止執行。  //判斷encoding的方法在Buffer模塊中,請參考前面的文章,文章地址,請在源碼分析的結尾查看。   // first, stat the file, so we know the size.  var size;  var buffer; // single buffer with file data  var buffers; // list for when size is unknown  var pos = 0;  var fd;   //參數驗證成功,開始執行讀取數據的,設置flag默認值  var flag = options.flag || 'r';  //首先根據路徑,打開文件,open的使用,請參考前面的文章  fs.open(path, flag, 438 /*=0666*/, function(er, fd_) {   //如果失敗,那么獲取到失敗的error對象,并返回該對象   if (er) return callback(er);    //記錄打開文件的文件描述符   fd = fd_;    //使用fstat,查看當前打開文件的一些基本信息。   //fstat獲取到的信息,請向前翻看。   fs.fstat(fd, function(er, st) {    if (er) {     //如果在執行fstat時失敗,則執行關閉文件的操作,     //關閉之后,把錯誤信息,傳入readFile的回調函數     return fs.close(fd, function() {      callback(er);     });    }     size = st.size;    //根據文件的大小,執行不同的操作    //如果為空文件,則重新定義一個空的buffers,執行read文件的方法    if (size === 0) {     // the kernel lies about many files.     // Go ahead and try to read some bytes.     buffers = [];     return read();    }    //如果文件內容,大于內存所能保存的最大量,則拋出一個范圍異常。    if (size > kMaxLength) {     var err = new RangeError('File size is greater than possible Buffer: ' + '0x3FFFFFFF bytes');     return fs.close(fd, function() {      callback(err);     });    }    //否則,定義一個與內容相當大小的Buffer對象,開始執行read方法    buffer = new Buffer(size);    read();   });  });   function read() {   //根據size的不同,執行兩個方法   //當讀取成功時,執行afterRead方法。   //其中,size,buffer,fd,pos,等都是父級作用域的變量   if (size === 0) {    buffer = new Buffer(8192);    fs.read(fd, buffer, 0, 8192, -1, afterRead);   } else {    fs.read(fd, buffer, pos, size - pos, -1, afterRead);   }  }   function afterRead(er, bytesRead) {   if (er) {    //讀取文件失敗時,根據失敗時的錯誤對象,執行readFile的回調函數    return fs.close(fd, function(er2) {     return callback(er);    });   }    //如果讀取的數據量為0,則表示已經讀取結束,則執行close方法,結束readFile方法,并返回數據   if (bytesRead === 0) {    return close();   }    //如果有值,則更改pos的值,也就是更改在read方法中,讀取文件起始位置的值。   pos += bytesRead;   //如果pos的值,已經等于文件的長度size了,則表示當前文件已經讀取結束了,則關閉文件   //否則,繼續調用read方法,繼續讀取。   //如果size===0的話,有可能是fstat沒有能正常的讀取到size的值,就執行后面的   if (size !== 0) {    if (pos === size) close();    else read();   } else {    // unknown size, just read until we don't get bytes.    //猜測,這里可能是在某些系統下,無法獲取到文件的字節數,所以添加的這個判斷。    buffers.push(buffer.slice(0, bytesRead));    read();   }  }   function close() {   fs.close(fd, function(er) {    //當文件讀取結束時,拼接讀取到的數組,    if (size === 0) {     // collected the data into the buffers list.     buffer = Buffer.concat(buffers, pos);    } else if (pos < size) {     buffer = buffer.slice(0, pos);    }    //根據是否有encoding,做一次編碼轉換    if (encoding) buffer = buffer.toString(encoding);    //把最終的數據,傳入readFile的回調函數中。    return callback(er, buffer);   });  } }; 

OK,上面就是源碼中,readFile的實現邏輯,源碼中,有提到了判斷encoding是否為當前支持的編碼方式的地方。

在前面我也說了句,在使用readFile時,設置flag的值,其實是無用的(我本人的想法,也可能是我資歷尚淺,沒有碰到過這樣的需求),但是不妨礙有些人為了測試或者好玩,對于readFile的時候,設置flag=“w+”的情況,當然這個時候,直接就報錯來吧。

前面的是readFile的相關東西,下面繼續看下寫文件的呢,也就是writeFile的方法來。

使用方法

fs.writeFile(fileName,data,[options],callback); 

其中:

  • fileName是表示您要操作的文件的地址,關于地址,請查看前面readFile方法時,注釋的鏈接。
  • data,為需要寫入的數據,可以直接是字符串,也可以是buffer數據。
  • options是讀取文件時,所需要的參數,options是一個對象,它只包含三個參數:options = { encoding: “utf-8”, flag: 'r' ,mode:438},這里的三個參數,其中encoding和flag和前面readFile所指代的含義相同,而mode所指代的含義,表示當前文件的操作權限,這個和fs.wirte時是相同的,可以參考:文本操作模塊-fs模塊(二)。
  • callback是回調函數,當改文件讀取成功時,執行該文件,并且callback方法支持兩個參數:

最簡單的示例:

var fs = require("fs");  fs.writeFile('test.js',"新添加的數據",{flag:"a+"},function(err,data){  if(err){   console.log("readFile file error");   return false;  }   console.log(data); }); 

這里說的示例,都是最簡單的示例,參數什么的,好多都沒有設置,因為在我看來,只要我能把源碼中相關的信息看懂,那么關于這些API的使用,我就可以幾乎找到它所有的使用方法,所以,在這里給出示例的時候,我都是給的一個最簡單的示例,然后后面繼續開始看下源碼中的信息,在源碼中,就可以把writeFile的使用方法,都能懂一些了。

writeFile源碼

繼續看下writeFile中的源碼實現邏輯,讓我們可以對writeFile有更深層次的了解。

function writeAll(fd, buffer, offset, length, position, callback) {  //判斷最后一個是否為回調函數,如果不是,給一個默認的回調函數  //默認的回調函數,在使用者來說,是無法訪問到的  callback = maybeCallback(arguments[arguments.length - 1]);   // write(fd, buffer, offset, length, position, callback)  //文件標志符是fd,需要寫入的數據是buffer,真實寫入數據,是從buffer的offset位置開始  //取長度為length的數據,寫入到fd指向的文件中,position的位置處。  fs.write(fd, buffer, offset, length, position, function(writeErr, written) {   if (writeErr) {    //如果寫入失敗,則關閉文件,執行callback,傳入失敗信息保存對象    fs.close(fd, function() {     if (callback) callback(writeErr);    });   } else {    //written為保存的數據byte值,如果意見全部保存,則保存完成,關閉文件    if (written === length) {     fs.close(fd, callback);    } else {     //如果沒有保存完畢,則更新offset,length,position的值,繼續調用該方法,     //保存剩下的數據,直到把所有的數據保存成功為止。     offset += written;     length -= written;     position += written;     writeAll(fd, buffer, offset, length, position, callback);    }   }  }); }  fs.writeFile = function(path, data, options, callback) {  //判斷最后一個是否為回調函數,如果不是,給一個默認的回調函數  var callback = maybeCallback(arguments[arguments.length - 1]);   //給options設置一些默認值,writeFile的第三個參數,只能是三種情況  //1:function,這個時候,options使用默認值,第三個參數為回調函數  //2:string類型,這個時候,第三個參數為encoding的屬性值  //3:object類型,這個時候,表示options為一個完整的對象,可能包含也可能不包含encoding和flag屬性  //如果不為上述的三種類型,那么直接拋出一個類型異常,停止執行  //這里的判斷和readFile基本完全一樣,只是默認值不一樣而已  if (util.isFunction(options) || !options) {   options = { encoding: 'utf8', mode: 438 /*=0666*/, flag: 'w' };  } else if (util.isString(options)) {   options = { encoding: options, mode: 438, flag: 'w' };  } else if (!util.isObject(options)) {   throw new TypeError('Bad arguments');  }   //判斷當前設置的encoding是否為當前支持的encoding,如果不支持,會拋出一個異常,  //停止繼續向下執行  assertEncoding(options.encoding);   //默認信息設置好,則打開文件,執行寫入操作  var flag = options.flag || 'w';  fs.open(path, flag, options.mode, function(openErr, fd) {   if (openErr) {    //打開失敗時,把失敗原因,傳入writeFile的回調函數    if (callback) callback(openErr);   }else {    //打開成功時,要把需要寫入的data信息,改為buffer對象    var buffer = util.isBuffer(data) ? data : new Buffer('' + data,options.encoding || 'utf8');    //判斷是否打開的方式,是否是追加模式,    //這里讓我很疑惑的一個問題是,為什么這里要用正則表達式?    //這樣簡單的判斷,直接食用indexOf,不是會有更高的效率?    // var position = flag.indexOf("a") == -1 ? 0 : null;    var position = /a/.test(flag) ? null : 0;    //準備好了所有的信息,則開始使用writeAll方法,寫入文件    writeAll(fd, buffer, 0, buffer.length, position, callback);   }  }); }; 

OK,writeFile的源碼就是這樣了,其實這里還有一個就是追加到文件的方法,命名為appendFile,這個就不單獨來寫了,看下源碼,應該就能懂了。

fs.appendFile = function(path, data, options, callback_) {  var callback = maybeCallback(arguments[arguments.length - 1]);   if (util.isFunction(options) || !options) {   options = { encoding: 'utf8', mode: 438 /*=0666*/, flag: 'a' };  } else if (util.isString(options)) {   options = { encoding: options, mode: 438, flag: 'a' };  } else if (!util.isObject(options)) {   throw new TypeError('Bad arguments');  }   if (!options.flag)   options = util._extend({ flag: 'a' }, options);   //調用的writeFile  fs.writeFile(path, data, options, callback); }; 

appendFile的源碼,就更沒有什么新東西了,只是做了一個判斷,然后給flag標簽添加了一個a屬性值,之后就直接調用的weiteFile的方法了。

總結

關于nodejs的操作文件,是比較重要的一個概念,所以包含的信息,也是比較多的,本篇依然是在之前open,read,write等的基礎上,執行的再一次的封裝,不屬于新的概念,只是為了能讓使用者更簡單的使用讀寫文件的功能而已。后面繼續在看一些其他的操作文件的API的功能及其實現。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持武林網。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
久久久亚洲国产天美传媒修理工| 国产欧美日韩中文字幕在线| 欧美色videos| 日韩精品欧美激情| 欧美国产日本在线| 一级做a爰片久久毛片美女图片| 久久噜噜噜精品国产亚洲综合| 欧美另类极品videosbestfree| 亚洲欧美成人精品| 日韩av在线看| 国产精品第一区| 国产女精品视频网站免费| 亚洲免费高清视频| 欧美另类极品videosbest最新版本| 欧美色欧美亚洲高清在线视频| 亚洲欧美激情视频| 成人免费网站在线看| 亚洲一区二区三区香蕉| 奇米一区二区三区四区久久| 夜夜嗨av色一区二区不卡| 久久久久免费视频| 国产午夜精品理论片a级探花| 国产日韩综合一区二区性色av| 91色琪琪电影亚洲精品久久| 国产精品欧美久久久| 亚洲天堂视频在线观看| 国产精品美女www| 韩剧1988免费观看全集| 日韩av中文字幕在线免费观看| 久久精品91久久久久久再现| 国产欧美亚洲视频| 国产精品丝袜一区二区三区| 欧美国产极速在线| 理论片在线不卡免费观看| 亚洲第一福利在线观看| 成人激情视频在线| 亚洲精品国产免费| 麻豆国产va免费精品高清在线| 尤物九九久久国产精品的分类| 欧美另类99xxxxx| 欧美一区三区三区高中清蜜桃| 国产成人极品视频| 久久伊人免费视频| 2020欧美日韩在线视频| 欧美性猛交xxxx乱大交蜜桃| 亚洲国产精品美女| 亚洲一区二区免费在线| 欧美在线观看网站| 国产亚洲精品久久久优势| 欧美日韩国产综合视频在线观看中文| 欧美黄色www| 国产精品久久久久91| 欧美电影在线观看完整版| 在线日韩欧美视频| 两个人的视频www国产精品| 青青精品视频播放| 91国偷自产一区二区三区的观看方式| 亚洲精品999| 亚洲成年人影院在线| 亚洲变态欧美另类捆绑| 欧美在线一区二区视频| 国产一区二区三区丝袜| 精品久久久中文| 欧美日韩一区免费| 亚洲天堂男人的天堂| 欧美黑人巨大精品一区二区| 自拍偷拍亚洲一区| 国产精品高潮粉嫩av| 日韩欧美中文字幕在线观看| 国产精品69久久久久| 美日韩精品免费视频| 日韩精品视频中文在线观看| 日韩在线免费视频| 久久亚洲综合国产精品99麻豆精品福利| 91最新国产视频| 日韩在线视频免费观看高清中文| 亚洲综合色激情五月| 亚洲免费电影一区| 国产美女搞久久| 欧美疯狂做受xxxx高潮| 性欧美亚洲xxxx乳在线观看| 97香蕉久久夜色精品国产| 日韩国产精品亚洲а∨天堂免| 成人激情在线观看| 国产精品亚洲美女av网站| 黑人与娇小精品av专区| 亚洲人成电影网站色…| 九九热这里只有精品6| 91免费看片网站| 69影院欧美专区视频| 欧美亚洲另类制服自拍| 中文日韩电影网站| 91午夜理伦私人影院| 国产精品18久久久久久麻辣| 欧美巨乳美女视频| 欧美影院成年免费版| 欧美在线观看日本一区| 在线观看精品国产视频| 狠狠色香婷婷久久亚洲精品| 欧美国产精品va在线观看| 91精品视频专区| 4k岛国日韩精品**专区| 一区二区日韩精品| 国产在线播放不卡| 精品国产一区二区三区久久| 国产亚洲免费的视频看| 欧美一区视频在线| 国产精品丝袜一区二区三区| 欧美精品制服第一页| 在线日韩欧美视频| www.欧美精品| 97在线看免费观看视频在线观看| 亚洲午夜未删减在线观看| 91在线视频九色| 亚洲无线码在线一区观看| 欧美自拍视频在线| 欧美日韩国产精品一区| 日韩电影视频免费| 精品国偷自产在线视频| 久久久国产精品视频| 欧美日韩国产精品一区二区三区四区| 国产日韩欧美视频| 色综合久久天天综线观看| 国产午夜精品美女视频明星a级| 美女国内精品自产拍在线播放| 久久天堂电影网| 久久精品最新地址| 91在线精品视频| 成人福利网站在线观看11| 日韩美女av在线| 国产精品第100页| 91人人爽人人爽人人精88v| 日韩在线激情视频| 欧美性xxxxx| 精品国产美女在线| 欧美最猛性xxxx| 国产97色在线|日韩| 色噜噜国产精品视频一区二区| 国产91精品黑色丝袜高跟鞋| 国产精品入口夜色视频大尺度| 国产精品18久久久久久麻辣| 最近2019年日本中文免费字幕| 色噜噜久久综合伊人一本| www.亚洲一区| 2020久久国产精品| 国产视频精品xxxx| 在线播放国产精品| 成人精品网站在线观看| 中文字幕久热精品视频在线| 欧美日韩第一视频| 91在线高清视频| 92版电视剧仙鹤神针在线观看| 亚洲少妇中文在线| 国产精品一区二区久久久久| 欧美国产高跟鞋裸体秀xxxhd| 久久久国产精品一区| 九九热99久久久国产盗摄| 亚洲精品美女久久| 色悠悠国产精品| 国产精品国产福利国产秒拍| 奇米影视亚洲狠狠色| 精品国产一区二区三区久久久| 91精品在线观| 操日韩av在线电影|