Node.js小白開路(一)-- fs篇

  文件操做在咱們的平常功能模塊之中是十分的常見的內容,nodeJS也不例外的爲咱們提供了之一操做內容,當時在咱們瞭解文件操做的以前咱們先來了解一下連接。node


   鏈接能夠理解成爲一個紙箱相關文件內容的地址,其主要分紅兩種,以下:數組

  1.符文鏈接內容:符文鏈接指向的文件其中的內容多半是指向另外一個文件的連接,有點像是咱們C語言中的指針的一個概念,指向的內容是指向另外一處內容模塊的指向,不知道C的朋友也能夠用window中的快捷方式來理解這樣只一個內容,桌面上面的快捷方式實際上其存儲的是實際開啓文件的位置。而咱們打開相關的快捷方式的時候是須要獲取這一文件連接的的。緩存

  2.硬連接:硬連接和符文鏈接的本質不一樣就在於其指向的文件是有實際內容的,好比我當前的目錄下面有一個文件內容testing.txt,這指向這一文件的連接就是一個硬連接。固然沒一個文件期初是有一個硬連接。app


  接下來咱們來具體的看一看文件操做模塊到底爲咱們帶來一些什麼樣的便利操做:異步

  一個文件有其本身的狀態,內容,權限等等,nodeJS之中爲咱們提供了不少針對文件這一系列數據的操做方法,讓咱們更好的把控和操做文件內容。socket

  #首先咱們來講一說文件的狀態內容。函數

    nodejs之中有專門的一個類內容用來描述咱們的文件的具體的狀態內容,那就是fs.Stats類,這一個類對象及時一個文件狀態屬性對象。其中具體的相關信息以下:性能

Stats {
  dev: 2114,  //硬件設備文件id
  ino: 48064969,  //節點編號
  mode: 33188,  //操做權限
  nlink: 1,  //硬連接數
  uid: 85,  //文件擁有者的id
  gid: 100,    //用戶組id
  rdev: 0,    //設備ID
  size: 527,  //文件字節量大小
  blksize: 4096, //文件磁盤區塊大小
  blocks: 8, //分配的512B大小區塊數量
  atimeMs: 1318289051000.1,
  mtimeMs: 1318289051000.1,
  ctimeMs: 1318289051000.1,
  birthtimeMs: 1318289051000.1,
  atime: Mon, 10 Oct 2011 23:24:11 GMT, //上次訪問時間
  mtime: Mon, 10 Oct 2011 23:24:11 GMT, //文件修改事件
  ctime: Mon, 10 Oct 2011 23:24:11 GMT,  //文件狀態變化時間
  birthtime: Mon, 10 Oct 2011 23:24:11 GMT } //文件建立時間  

上面可見咱們能夠從這一對象中獲取的內容,nodeJS中如何來獲取這一對象內容呢:咱們能夠經過fs.stat,fs.fstat等方法。學習

咱們下面來具體的說明一下這兩個方法吧。測試

  -- fs.stat(path, callback):函數獲取當前文件的狀態並檢測文件是否能夠正確打開。兩個參數path表示文件路徑內容,callback爲回調函數內容,咱們在編寫回調函數的時候要爲其提供一個參數內容err,系統自動傳遞參數,當發生錯誤的狀況下則有error對象內容傳遞,若是正常則直接傳遞空對象或是null/undefined,下面看一段代碼:

fs.stat('../testing/test.txt', (err,stats) => {
    if(err){
        console.log(err.message);   
    }
    else {
        console.dir(stats);
    }
});

上面是對應的結果。

  -- fs.fstat(fd, callback):這一個函數的功能和上一個函數相同,只是這一函數內容的第一個參數內容再也不是路徑而是文件描述符,什麼是描述符,咱們經過nodeJS來打開文件內容的時候會返回一個特別的文件描述符內容,實際上它打印出來就是一個數字內容而已。下面來看一段代碼內容。

fs.open('../testing/test.txt', 'r' ,(err, fd) => { //打開相關文件內容獲取描述符
    fs.fstat(fd, (err, stats) => {
        if(err){
            console.log(err.message);
        }
        else {
            console.dir(stats);
        }
    });
});

獲取結果與上一段代碼獲取的結果相同。 

  -- fs.lstat(path, callback):這一函數也是相關文件信息獲取函數,其傳遞的參數與stat函數的內容是相同的,可是兩個函數的功能差異就在於這一個函數在獲取的path是指向符號連接文件的時候,會獲取當前符號文件內容的stats信息,而stat方法會自動的去獲取當前的符號文件指向的文件內容。 


 

  下面咱們來看看fs之中文件內容的操做有哪些咱們是可使用的。

  首先咱們可能會想到的是連接一下咱們的文件試試看。

  -- fs.access(path [, mode], callback):測試文件的權限內容。

   #path:文件的路徑內容。

   #mode:文件權限模式,默認是fs.constants.F_OK

   #callback:文件的回調函數內容。

  當咱們檢測的可訪問性失敗了,則會報錯。不然正常。這屬於一個檢測性質的文件內容。可是nodeJS內容並不推薦這樣作,咱們在異步的檢測文件內容以後,因爲有一段時間的數據返回的空擋,咱們的文件權限類型有可能發生變化,和咱們所檢測到的相關內容不相同,因此在作文件的其餘的操做以前進行檢測是不推薦的。咱們能夠直接使用open函數來進行文件的打開,它同時也是會進行相關的檢測的。

 

  當咱們須要打開以個文件的時候,咱們能夠經過nodeJS之中的open方法來實現咱們的操做。(當沒有這一文件的時候,open會依據傳遞內容建立一個相應的文件內容。)

  -- fs.open(path, flags [, mode], callback):這裏重點說明一下flags參數內容,表示的是打開文件的模式,其中涵蓋了用戶對當前的額文榮的操做權限其具體的內容以下列表

'r' - 以讀取模式打開文件。若是文件不存在則發生異常。

'r+' - 以讀寫模式打開文件。若是文件不存在則發生異常。

'rs+' - 以同步讀寫模式打開文件。命令操做系統繞過本地文件系統緩存。

這對 NFS 掛載模式下打開文件頗有用,由於它可讓你跳過潛在的舊本地緩存。 它對 I/O 的性能有明顯的影響,因此除非須要,不然不要使用此標誌。

注意,這不會使 fs.open() 進入同步阻塞調用。 若是那是你想要的,則應該使用 fs.openSync()。

'w' - 以寫入模式打開文件。文件會被建立(若是文件不存在)或截斷(若是文件存在)。

'wx' - 相似 'w',但若是 path 存在,則失敗。

'w+' - 以讀寫模式打開文件。文件會被建立(若是文件不存在)或截斷(若是文件存在)。

'wx+' - 相似 'w+',但若是 path 存在,則失敗。

'a' - 以追加模式打開文件。若是文件不存在,則會被建立。

'ax' - 相似於 'a',但若是 path 存在,則失敗。

'a+' - 以讀取和追加模式打開文件。若是文件不存在,則會被建立。

'ax+' - 相似於 'a+',但若是 path 存在,則失敗。

上面所說的是flags之中傳遞的參數內容,下面咱們在來講明一下mode內容的,mode表示的是文件權限和文件類型信息。這麼一說有沒有感受flags和mode有些相像,其實能夠這麼理解,flags實際上使用戶的操做模式,其給定的一種操做模式,好比讀取模式,而當這次操做形式超出了讀取模式的權限的時候將不會成功,而當咱們設置mode內容的時候,其實是直接設置了文件自己的相關信息。因此二者之間並不衝突。那麼mode參數能夠傳遞哪些值呢:

文件類型標誌包括:

S_IFBLK:文件是一個特殊的塊設備

S_IFDIR:文件是一個目錄

S_IFCHR:文件是一個特殊的字符設備

S_IFIFO:文件是一個FIFO設備

S_IFREG:文件是一個普通文件(REG即便regular啦)

S_IFLNK:文件是一個符號連接

其餘模式標誌包括:

S_ISUID:文件設置了SUID位

S_ISGID:文件設置了SGID位

S_ISVTX:文件設置了sticky位

用於解釋st_mode標誌的掩碼包括:

S_IFMT:文件類型

S_IRWXU:屬主的讀/寫/執行權限,能夠分紅S_IXUSR, S_IRUSR, S_IWUSR

S_IRWXG:屬組的讀/寫/執行權限,能夠分紅S_IXGRP, S_IRGRP, S_IWGRP

S_IRWXO:其餘用戶的讀/寫/執行權限,能夠分爲S_IXOTH, S_IROTH, S_IWOTH

還有一些用於幫助肯定文件類型的宏定義,這些和上面的宏不同,這些是帶有參數的宏,相似與函數的使用方法:

S_ISBLK:測試是不是特殊的塊設備文件

S_ISCHR:測試是不是特殊的字符設備文件

S_ISDIR:測試是不是目錄(我估計find . -type d的源代碼實現中就用到了這個宏)

S_ISFIFO:測試是不是FIFO設備

S_ISREG:測試是不是普通文件

S_ISLNK:測試是不是符號連接

S_ISSOCK:測試是不是socket

上面的一系列值咱們稱之爲宏定義,當咱們須要傳值的狀況下,咱們須要傳遞的是多個宏定義的組合值,通俗的來講其實每個宏定義是一個特殊的二進制內容變量。咱們使用這些值與按位與(&)的形式來組合不一樣的內容。

以後咱們來看一段代碼:

fs.open('../testing/test.txt', 'r' ,(err, fd) => {
    if(err){
        console.log(err.message);
    }
    else {
        console.dir(fd);
    }
});
//結果爲3

  

  當咱們打開文件內容以後要對頁面內容進行操做。

  文件讀取內容內容。在文編唄打開以後咱們獲取了相關的文件描述符內容,以後咱們就能夠進行對這一針對性文件的操做內容。讀取文件內容I/O操做從磁盤之中將咱們須要的內容存放到緩存之中。下面咱們來了解一下讀取函數內容。

  -- fs.read(fd, buffer, offset, length, position, callback):讀取文件中制定位置的內容到緩存對象之中。

   #fd:表示的是相關的文件的描述符內容。

   #buffer:是存放讀取到的數據的Buffer對象。

   #offset:是Buffer之中開始寫入的偏移量。

   #length:指定要讀取的字節數。

   #position:指定從文件中開始讀取的位置。

   #callback:回調函數內容其中有三個參數內容(err, bytesRead, buffer)

    err表示是否有錯誤,若是有的這傳遞相關的錯誤信息。

    bytesRead:讀取的文件內容的長度。

    buffer:爲最終獲取的字符串內容。

讓咱們來看一段示例代碼內容吧:

var buf = Buffer.alloc(10);
fs.open('../testing/test.txt', 'r', (err, fd) => {
    if(err){
        console.log(err.message);   
    }
    else {
        fs.read(fd, buf, 1, 9, 0, (err, bytesRead, buffer) => {
            if(err){
                console.log(err.message);   
            }
            else{
                console.dir(bytesRead);
                console.dir(buffer);
            }
            console.log(buf);
        });   
    }
});

咱們能夠從圖中看到的,Buffer的內容是不相同的,可是若是咱們調用toString()方法的話,咱們能夠看到,實際上二者展現出來的內容是相同的。這是應爲返回來的內容第二個內容數據爲10進制的,而以後展現出來的Buffer內容則爲16進制的。

 

  固然讀取方法不僅僅只有一個。

  -- fs.readFile(path [,option], callback):這一函數用於讀取文件的所有內容,傳遞的參數內容內容以下:

   #path:文件路徑或是文件描述符。

   #option:傳遞的選填參數內容,能夠傳遞string也能夠是對象內容。

    - encoding:編碼格式內容。

    - flags:文件操做權限,默認爲‘r’。

   #callback:回調函數內容其中有兩個參數須要傳遞。

    - err:錯誤信息。

    - data:數據內容。

咱們來看一段代碼。

fs.readFile('../testing/test.txt', (err, data) => {
    if(err){
        console.log(err.message);
    } else {
        console.dir(data);  
        console.log(data.toString());
    }
});

其結果就是

  

  當文件被打開以後咱們可能不只僅須要讀取,可能還須要對文件內容進行修改或者是寫入操做等,這樣咱們要經過怎麼樣的方式來進行操做呢。

  -- write(fd, buffer [, position [, encoding]], callback):寫入Buffer文件內容到fd標識符之中。

   #fd:表示的將要寫入的文件描述符內容。

   #buffer:寫入文件之中的相關的緩存內容。

   #position:文件錄入內容起始位置Bufffer的起始位置。

   #encoding:文件編碼格式。

   #callback:回掉函數內容

    - err:錯誤相關信息。

    - written:傳遞進入的參數內容長度(多少字節)。

    - string:寫入的內容是什麼。

下面看到一段代碼:

fs.open('../testing/test.txt', 'r+', (err, fd) => {
    fs.write(fd, Buffer.from(' something'), (err, written, buffer) => {
        console.log(written);
        console.dir(buffer);
    });
});

 經過上面這一段代碼內容咱們能夠爲test.txt文件添加內容‘ semothing’而且內容是將本來內容進行個替換,而不是進行插入添加。可是替換的內容只是在與其輸入的字符串長度等長度的部份內容。可是,當咱們修改了open傳遞的flag信息的時候,當flags內容傳遞成爲W或者是W+的狀況之下咱們在使用write函數的時候將會將整個文件內容替換掉。還有就是當咱們在flags傳遞的內容是r的時候咱們是不能進行寫操做的。

 

  -- fs.writeFile(file, data [,options], callback):異步地寫入數據到文件,若是文件已經存在,則替代文件。

   #file:能夠是文件路徑或者是文件描述符。

   #data:傳遞將要寫入的文件內容。

   #options:能夠傳遞一個字符串或者是一個對象內容。

    -encoding:文件編碼格式。

    -mode:文件權限模式設置。

    -flag:文件操做權限。

   #callback:回掉函數內容傳遞嘗試內容(err)。

咱們來看一段代碼

fs.writeFile('../testing/test.txt', 'there is a something', (err) => {});  //結果就是文件內容被替換成爲傳遞的內容。

 

  固然咱們也可使用流來進行文件的操做。 建立可讀流內容  

  -fs. createReadStream(path [,option]): 

   #path:文件內容路徑。

   #option:非必填,能夠是string或是對象。

    -flags:文件操做權限

    -encoding:path的編碼格式

    -fd:文件描述符文件,若是傳遞了fd則默認不適用path,

    -mode:文件的操做模式

    -autoClose:當有錯誤或是結束了當前流的時候會依據此參數來肯定當前的fd是否會自動的關閉。若是不關閉的話代碼之中要注意自助關閉,不然可能會泄露

    -start:文件開始讀取的偏移量。

    -end:文件結束的偏移量。

  咱們來具體的看一段代碼吧。

 

var readS = fs.createReadStream('../testing/test.txt', {flags:'r+'});
console.dir(readS);.//獲取的相關結果是,一個閱讀流。 

 具體的流內容的操做咱們能夠在流篇章看見。

  固然咱們實際上也是能夠建立一個可寫流的。

  -- fs.createWriteStream(path [,option]):建立可寫流內容其中的傳遞的內容實際和建立可讀流的時候是相同的狀況,因此當咱們使用的也是須要注意的。

 

  咱們同時也能夠追加相關的文件內容

  -- fs.appendFile(file,data [,options], callback):一步的最佳數據到相關的文件內容,當咱們的文件不存在的時候,則函數會自動的建立這一文件內容。

   #path:文件路徑內容。

   #data:想要追加的數據內容,String, Buffer

   #options:能夠是一個string或者是一個對象內容。

    -encoding:編碼格式內容。

    -mode:文件的權限格式類型。

    -flag:用戶對文件的操做權限。

   #callback:文件的回調函數內容。

上代碼。

fs.appendFile('../testing/test.txt', ', check appendFile', (err) => {});

結果是,在文件的末尾添加了當前傳遞的data參數內容。

 

  咱們有的時候須要對文件內容進行拷貝操做這個時候咱們就能夠經過copyFile,

  -- fs.copyFile(src, dest [,flags], callback):複製文件內容,到指定的路徑文件下。

   #src:須要複製的文件路徑內容。

   #dest:指定的文件路徑內容。

   #flags:拷貝操做修飾符。

   #callback:回調函數。

咱們來看一段代碼。

fs.copyFile('../testing/test.txt', './test.txt', (err) => {});

 

  最後當咱們操做完成以後咱們須要關閉文件內容,這樣一面咱們緩存之中的內容被泄露。

  -- fs.close(fd, callback):文件關閉

   #fd:文件描述符。

   #callback:文件回調函數。

 

  固然咱們有時須要對於文件夾進行操做。

  -- fs.mkdir(path [,mode], callback):建立一個文件路徑。

   #path:建立文件夾的路徑

   #mode:文件夾權限模式。

   #callback:回調函數內容

  -- fs.mkdtemp(prefix [,options], callback):建立一個惟一的臨時目錄

    #prefix:參數爲建立臨時文件的路徑。建立臨時時會自動生成一個惟一序列 

   #mode:文件夾的權限模式

   #callback:回調函數內容。

 

  固然咱們也能夠對於讀取文件夾之中的內容。

  -- fs.readdir(path [,options] , callback): 讀取文件夾內容。

   #path:爲須要查詢的文件夾內容。

   #callback:回調函數。其中有兩個參數內容,err爲錯誤信息,第二個參數爲file爲當前文件夾之名稱不存在‘.’ '..'的文件名稱所組成的數組。

代碼示例

fs.readdir('../testing', (err,stats) => {console.dir(stats)});

結果相似以下


  文件內容操做以外,咱們還能夠針對文件權限或是狀態內容進行相關的修改或是操做。

  -- fs.chomd(path, mode, callback):賦予當前path文件以mode之中的文件模式。

   #path:文件路徑。

   #mode:文件權限。

   #callback:回調函數內容。

  文件權限內容能夠看上文之中的mode介紹內容。

  -- fs.chown(path, uid, gid, callback):改變文件的全部組。

   #path:文件路徑內容。

   #uid:用戶ID。

   #gid:組別ID。

   #callback:回調函數。

  -- fs.fsync(fd,callback):同步當前的內容到文件

   #fd:文件描述符。

   #callback:文件內容

  -- fs.ftruncate(fd [,len], callback):文件截斷到指定的長度。

   #fd:文件描述符。

   #len:文件長度。

   #callback:回調函數。

  -- fs.futimes(fd, atime, mtime, callback):改變文件的系統時間戳。

   #fd:文件描述符。

   #atime:文件連接時間。

   #mtime:文件修改時間。

   #callback:回調函數。

 

固然FS模塊爲咱們提供的將不只僅是上面這一些內容,當前只是比較基礎的內容的學習。參照的文本包括官方文檔和node權威指南內容。

相關文章
相關標籤/搜索