测验:NodeJS IO 精通
测试你对文件、流与缓冲区的掌握
准备好深入 NodeJS IO 的世界了吗?🌊
这个测验将测试你对 Node IO 操作的理解,从基本的文件系统操作到高级的流式概念。我们会涵盖缓冲区、编码以及高效处理数据的最佳实践。
来看看你对流和缓冲区的掌握程度吧!🚀
这段代码做了什么?
const buf = Buffer.alloc(5);console.log(buf);Buffer.alloc(size) 创建一个指定大小的新缓冲区,并用零填充。
输出将是:<Buffer 00 00 00 00 00>
如果你想创建一个包含随机数据的缓冲区,请使用 Buffer.allocUnsafe(5)。
这会打印什么?
const buf = Buffer.from([65]);console.log(buf.toString());输出顺序是什么?
import fs from 'fs';fs.readFile('test.txt', 'utf8', (err, data) => { console.log(data);});console.log('Done');由于 readFile 是异步的,代码在读取文件时会继续执行。
因此,“Done” 会在文件内容之前打印。
如果要等待文件先读取完成,可以使用基于 Promise 的版本:
import { promises as fs } from 'fs';
async function read() { const data = await fs.readFile('test.txt', 'utf8'); console.log(data); console.log('Done');}默认情况下,fs.readFileSync() 返回什么?
import fs from 'fs';const content = fs.readFileSync('test.txt');默认情况下,当未指定编码时,fs.readFileSync() 返回一个 Buffer。如果你想要一个字符串,你需要:
- 指定编码:
fs.readFileSync('test.txt', 'utf8') - 转换 Buffer:
content.toString()
哪一组事件通常用于可读流?
可读流会触发几个重要事件:
- ‘data’: 当有数据可读时
- ‘end’: 当没有更多数据可读时
- ‘error’: 当发生错误时
- ‘close’: 当流和底层资源关闭时
const readable = fs.createReadStream('file.txt');readable.on('data', chunk => console.log(chunk));readable.on('end', () => console.log('Done!'));这段代码做了什么?
import fs from 'fs';const readable = fs.createReadStream('source.txt');const writable = fs.createWriteStream('dest.txt');readable.pipe(writable);pipe() 将可读流连接到可写流,自动管理背压并以块的形式复制数据,而无需将整个文件加载到内存中。
与先使用 fs.readFile() 再使用 fs.writeFile() 相比,这种方法对于大文件来说内存效率更高。
recursive 选项的作用是什么?
import fs from 'fs';fs.mkdirSync('./a/b/c', { recursive: true });recursive: true 选项会在父目录不存在时创建它们。
如果没有这个选项,尝试创建 ’./a/b/c’ 时,如果 ’./a’ 或 ’./a/b’ 不存在,则会抛出错误。
这类似于 shell 命令 mkdir -p。
这段代码会输出什么?
import { Transform } from 'stream';const upperCase = new Transform({ transform(chunk, encoding, callback) { callback(null, chunk.toString().toUpperCase()); }});process.stdin .pipe(upperCase) .pipe(process.stdout);// Input: "hello world"当文件被修改时,fs.watch() 保证触发多少次?
import fs from 'fs';fs.watch('test.txt', (eventType, filename) => { console.log(`${filename} was changed`);});// Then modify test.txt oncefs.watch() 不保证每次逻辑文件更改恰好触发一次。它经常多次触发,因为许多文本编辑器:
- 保存到临时文件
- 重命名为目标文件
为了更可靠的监视,考虑使用:
chokidar包- 防抖回调
- 使用
fs.watchFile()(虽然效率较低)
输出是什么?
const buf1 = Buffer.from('Hello');const buf2 = Buffer.from('Hello');console.log(buf1 === buf2);缓冲区是通过引用进行比较,而不是值。即使它们包含相同的数据,它们也是不同的对象。
要比较缓冲区的内容,请使用:
buf1.equals(buf2) // true// orBuffer.compare(buf1, buf2) === 0 // true流背压的主要目的是什么?
背压是一种机制,当写入端跟不上时暂停读取,从而防止内存溢出。
手动背压示例:
readable.on('data', (chunk) => { const canContinue = writable.write(chunk); if (!canContinue) { readable.pause(); writable.once('drain', () => readable.resume()); }});pipe() 会自动处理!
这段代码做了什么?
import fs from 'fs';fs.symlinkSync('target.txt', 'link.txt');symlinkSync 创建一个指向目标文件的符号链接(类似于快捷方式)。
与硬链接的主要区别:
- 可以链接到目录
- 可以跨文件系统
- 如果目标被删除则失效
要创建硬链接,请使用:
fs.linkSync('target.txt', 'hardlink.txt');Node.js 流可以以哪些模式运行?
流可以以以下模式运行:
- 二进制模式(默认):用于缓冲区和字符串
- 对象模式:用于任何 JavaScript 值
对象模式示例:
import { Transform } from 'stream';const objectStream = new Transform({ objectMode: true, transform(chunk, encoding, callback) { callback(null, { value: chunk }); }});这个回调中的 fd 参数是什么类型?
import fs from 'fs';fs.open('test.txt', 'r', (err, fd) => { console.log(typeof fd);});文件描述符是操作系统中唯一标识打开文件的数字。
前三个文件描述符是保留的:
- 0:标准输入
- 1:标准输出
- 2:标准错误
始终记得关闭文件描述符:
fs.close(fd, (err) => { if (err) throw err;});这个字符串在 UTF-8 编码下占用多少字节?
const str = "Hello 🌍";const buf = Buffer.from(str);console.log(buf.length);在 UTF-8 中:
- ASCII 字符(如 ‘Hello ‘)每个占 1 字节
- 地球表情 🌍 占 4 字节
因此:5(Hello)+ 1(空格)+ 4(🌍)= 10 字节
查看字节的方法:
console.log(buf); // <Buffer 48 65 6c 6c 6f 20 f0 9f 8c 8d>我希望你喜欢测试你的NodeJS IO知识!想要更多?看看我的测验合集获取更多挑战!