極簡 Node.js 入門 - 3.2 文件讀取


極簡 Node.js 入門系列教程:https://www.yuque.com/sunluyong/node

本文更佳閱讀體驗:https://www.yuque.com/sunluyong/node/fs-read

Node.js 提供了多種讀取文件的 API

fs.readFile

fs.readFile(path[, options], callback) 是最常用的讀取文件方法,用於異步讀取文件的全部內容

const fs = require('fs');

fs.readFile('./test.txt', (err, data) => {
  if (err) throw err;
  console.log(data);
});

回調會傳入兩個參數 (err, data),其中 data 是文件的內容,如果 options 是字符串,則它指定字符編碼:

fs.readFile('./test.txt', 'utf8', callback);

options 可以設置為對象

fs.readFile('./test.txt', { encoding: 'utf8', flag: 'r' }, callback);

fs.open、fs.read、fs.close

fs.readFile 使用相當簡單,在大部分讀取小文件的時候我們都應該使用這個方法,但 fs.readFile() 會把文件全部內容讀取,如果想精確讀取部分文件內容,Node.js 也提供了類似 C 語言 fopen、fgetc、fclose 的操作

在 Node.js 中讀取一個文件同樣有三步

  1. fs.open():分配(打開)文件描述符
  2. fs.read():讀取文件內容
  3. fs.close():關閉文件描述符

> 在 POSIX 每個打開的文件系統都分配了一個稱為文件描述符的數字。 文件系統操作使用文件描述符來標識和跟蹤每個特定的文件。一旦被分配,則文件描述符可用於從文件讀取數據、向文件寫入數據、或請求關於文件的信息 > buffer 相關知識需要先行查看 > [Buffer](https://www.yuque.com/sunluyong/node/buffer) 章節 ### fs.open(path[, flags[, mode]], callback) 通過 fs.open 方法可以打開一個文件,獲取分配到的文件描述符,方法參數含義:
  • path 文件路徑(實際還能是 Buffer、URL)
  • flags 文件標志位,默認值 r(read 縮寫),標識文件用於讀取
  • mode 文件模式,默認值 0o666 (rw-)可讀寫
  • callback
    • err
    • fd 分配到的文件描述符 (file description)

fs.read(fd, [options,] callback)

fs.read 用於從文件描述符中讀取數據,方法參數含義:

  • fd 文件描述符
  • options 可選項,不設置使用下述默認值
    • buffer:數據(從 fd 讀取)將被寫入的緩沖區,默認會申請一個新的緩沖區 Buffer.alloc(16384)
    • offset:buffer 開始寫入的偏移量,默認值為 0
    • length:需要讀取的字節數,默認使用 buffer.length
    • position:從文件中開始讀取數據的位置;如果 position 為 null,則從當前文件位置讀取,並重置文件位置到上次位置;如果 position 是整數,則文件位置會被保持。默認值為 null
  • callback
    • err
    • bytesRead
    • buffer

fs.read 還有一個需要把參數寫全的重載 fs.read(fd, buffer, offset, length, position, callback)

fs.close(fs, callback)

fs.close 用於關閉文件描述符,大多數操作系統都會限制同時打開的文件描述符數量,因此當操作完成時關閉描述符非常重要。 如果不這樣做將導致內存泄漏,最終導致應用程序崩潰

demo

test.txt

0123456789
abcdefghigklmnopqrstuvwxyz
ABCDEFGHIJKLMNOPQRSTUVWXYZ
const fs = require('fs');
const promisify = require('util').promisify;

const open = promisify(fs.open);
const read = promisify(fs.read);
const close = promisify(fs.close);

async function test() {
  const fd = await open('./test.txt');
  const readOptions = {
    // buffer: Buffer.alloc(26), 異步調用默認可以不設置,如果希望讀取的字節寫入指定的緩沖區可以指定
    position: 11, // 從第 11 個字節開始讀取,讀取后文件位置被重置
    length: 26, // 讀取 26 個字節
  };

  const { bytesRead: bytesRead1, buffer: buf1  } = await read(fd, readOptions);

  console.log(`第一次讀取字節數: ${bytesRead1}`);
  console.log(`第一次讀取數據內容: ${buf1.toString()}`);

  // 不指定 position,文件位置每次讀取后會保持
  const { bytesRead: bytesRead2, buffer: buf2 } = await read(fd, { length: 1 });
  console.log(`第二次從文件重置后位置讀取 ${bytesRead2} 字節內容: ${buf2.toString()}`);

  const { bytesRead: bytesRead3, buffer: buf3 } = await read(fd, { length: 1 });
  console.log(`第三次從文件當前位置讀取 ${bytesRead3} 字節內容: ${buf3.toString()}`);

  await close(fd);
  console.log(`文件描述符 ${fd} 已關閉`);
}

test();
第一次讀取字節數: 26
第一次讀取數據內容: abcdefghigklmnopqrstuvwxyz
第二次從文件重置后位置讀取 1 字節內容: 0
第三次從文件當前位置讀取 1 字節內容: 1
文件描述符 20 已關閉
  • 程序第一次從第 11 個字節開始讀取 test.txt 內容,一共讀取 26 個字節
  • 第一次讀取設置了 position 屬性,讀取完成后文件指針位置被重置為 0
  • 第二次讀取沒有設置 position 讀取一個字節后,文件位置停留在 1
  • 第三次讀取直接從文件位置 1 開始讀取


除非希望精確控制,否則不要使用這種方式讀取文件,手工控制緩沖區、文件位置指針很容易出現各種意外狀況

fs.createReadStream

對於大文件讀取一般使用流的方式,關於流的簡單原理在后面章節有專門介紹,本章介紹一下使用 fs 創建可讀文件流
fs.createReadStream(path[, options])

  1. path
  2. options(比較常用的有)
    • fd: 如果指定了 fd,則 ReadStream 會忽略 path 參數,使用指定的文件描述符(不會再次觸發 open 事件)
    • autoClose: 默認值: true,文件讀取完成或者出現異常時是否自動關閉文件描述符
    • start: 開始讀取位置
    • end: 結束讀取位置
    • highWaterMark: 默認值: 64 * 1024,普通可讀流一般是 16k


流的各個狀態會有對應的事件拋出,還是讀取上文用過的 test.txt 文件

const fs = require('fs');

const rs = fs.createReadStream('./test.txt', { start: 11, end: 36 });

rs.on('open', fd => {
  console.log(`文件描述符 ${fd} 已分配`);
});

rs.on('ready', () => {
  console.log('文件已准備好');
});

rs.on('data', chunk => {
  console.log('讀取文件數據:', chunk.toString());
});

rs.on('end', () => {
  console.log('文件讀取完成');
});

rs.on('close', () => {
  console.log('文件已關閉');
});

rs.on('error', (err) => {
  console.log('文件讀取發生發生異常:', err.stack);
});
文件描述符 20 已分配
文件已准備好
讀取文件數據: abcdefghigklmnopqrstuvwxyz
文件讀取完成
文件已關閉

可讀流詳細操作參考:可讀流 https://www.yuque.com/sunluyong/node/readable


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM