Node.js 本身沒有像 Java 那樣嚴格區分字符流和字節流,區別主要靠編碼(encoding)來控制數據是以 Buffer(二進制字節)形式還是字符串(字符)形式處理。
詳細解釋:
方面 | Java | Node.js |
---|---|---|
字節流 | InputStream / OutputStream | 默認情況下的 Readable / Writable 流,數據是 Buffer(二進制) |
字符流 | Reader / Writer | 流上設置 encoding ,數據自動轉換成字符串(UTF-8、ASCII 等) |
編碼處理 | 字節流和字符流類分開,編碼需自己控制 | Buffer 是二進制字節,設置 encoding 自動轉換成字符 |
示例 | FileInputStream vs FileReader | fs.createReadStream + encoding 參數 |
API差異 | 不同基類,區別明顯 | 同一套流 API,參數控制返回類型 |
舉個 Node.js 代碼例子說明:
const fs = require('fs');// 字節流(默認,讀取到 Buffer)
const stream1 = fs.createReadStream('file.txt');
stream1.on('data', chunk => {console.log(Buffer.isBuffer(chunk)); // true,收到的是 Buffer(二進制)
});// 字符流(設置編碼,讀取到字符串)
const stream2 = fs.createReadStream('file.txt', { encoding: 'utf8' });
stream2.on('data', chunk => {console.log(typeof chunk); // string,收到的是字符串
});
總結
-
Node.js 流是統一的“字節流”,數據默認是 Buffer 類型的二進制。
-
通過給流設置
encoding
,Node.js 會自動將字節流轉換成字符串,達到類似 Java 字符流的效果。 -
Java 是在類結構上區分字符流和字節流;Node.js 是靠參數和 Buffer 來決定處理方式。
如果你做文件操作,想“像用字符流一樣”處理文本,就用帶編碼的流;如果要處理二進制數據,就用默認的 Buffer 流。
你想了解 Node.js 里跟文件讀取(以及文件操作)相關的常見函數,尤其是跟“讀取(read)”、“讀文件(readFile)”、“創建(create)”、“流(stream)”有關的。順便幫你補充一些常用但你沒說的相關函數。
我幫你把 Node.js 文件系統(fs
模塊)相關常用方法做個全面的梳理和舉例。
Node.js 文件讀寫相關函數大全
1. fs.readFile()
和 fs.readFileSync()
-
作用:一次性讀取整個文件內容(異步和同步版本)
-
示例:
const fs = require('fs');// 異步讀文件
fs.readFile('example.txt', 'utf8', (err, data) => {if (err) throw err;console.log('異步讀文件內容:', data);
});// 同步讀文件
const content = fs.readFileSync('example.txt', 'utf8');
console.log('同步讀文件內容:', content);
2. fs.read()
-
作用:讀取文件的部分內容(基于文件描述符,低級 API)
-
需要先打開文件,得到文件描述符(fd)
-
示例:
const fs = require('fs');fs.open('example.txt', 'r', (err, fd) => {if (err) throw err;const buffer = Buffer.alloc(10); // 讀取10字節fs.read(fd, buffer, 0, 10, 0, (err, bytesRead, buf) => {if (err) throw err;console.log('讀取字節數:', bytesRead);console.log('讀取內容:', buf.toString('utf8', 0, bytesRead));fs.close(fd, (err) => {if (err) throw err;});});
});
3. fs.createReadStream()
-
作用:創建一個可讀流,適合大文件或流式處理
-
示例:
const fs = require('fs');const readStream = fs.createReadStream('example.txt', { encoding: 'utf8', highWaterMark: 16 * 1024 });readStream.on('data', (chunk) => {console.log('讀取到數據塊:', chunk);
});readStream.on('end', () => {console.log('讀取完畢');
});readStream.on('error', (err) => {console.error('讀取錯誤:', err);
});
4. fs.open()
/ fs.close()
-
作用:打開文件,返回文件描述符(fd),用于更底層操作;操作結束后關閉文件
-
示例:
fs.open('example.txt', 'r', (err, fd) => {if (err) throw err;console.log('文件描述符:', fd);fs.close(fd, (err) => {if (err) throw err;console.log('文件已關閉');});
});
5. fs.readSync()
-
同步版本的
fs.read()
,基于 fd 讀文件部分內容 -
示例:
const fd = fs.openSync('example.txt', 'r');
const buffer = Buffer.alloc(10);
const bytesRead = fs.readSync(fd, buffer, 0, 10, 0);
console.log(buffer.toString('utf8', 0, bytesRead));
fs.closeSync(fd);
6. fs.readv()
/ fs.readvSync()
(Node.js 12+)
-
作用:一次讀取多個 buffer(分散讀)
-
相對較少用,進階用法
7. 其它相關的文件讀取與創建函數
函數 | 說明 | 同步/異步 |
---|---|---|
fs.writeFile() / fs.writeFileSync() | 寫文件(覆蓋寫) | 異步/同步 |
fs.appendFile() / fs.appendFileSync() | 追加寫文件 | 異步/同步 |
fs.createWriteStream() | 創建寫流 | 適合大文件或流式寫入 |
fs.exists() / fs.existsSync() | 判斷文件是否存在(不推薦,建議用 fs.stat ) | 異步/同步 |
fs.stat() / fs.statSync() | 獲取文件信息(大小、時間等) | 異步/同步 |
fs.readdir() / fs.readdirSync() | 讀取目錄下文件列表 | 異步/同步 |
8. 結合 stream
讀取文件示例
const fs = require('fs');
const { pipeline } = require('stream');const readStream = fs.createReadStream('example.txt', { encoding: 'utf8' });
readStream.on('data', (chunk) => {console.log('讀取塊:', chunk);
});
readStream.on('end', () => {console.log('讀完了');
});
9. readline
模塊按行讀取大文件
const fs = require('fs');
const readline = require('readline');const rl = readline.createInterface({input: fs.createReadStream('example.txt'),crlfDelay: Infinity
});rl.on('line', (line) => {console.log(`一行: ${line}`);
});rl.on('close', () => {console.log('文件讀取結束');
});
總結
-
簡單快速讀小文件用
fs.readFile()
或同步版本 -
**讀文件片段(低級)**用
fs.read()
+fs.open()
-
大文件流式讀用
fs.createReadStream()
-
按行讀可以結合
readline
模塊 -
底層操作使用
fs.open()
、fs.read()
、fs.close()
如果你想,我還可以幫你整理寫文件相關的函數用法,或者把流式讀寫結合的完整例子也給你,告訴我哈!