news 2026/4/18 9:51:48

fs.promises 深入全面讲解

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
fs.promises 深入全面讲解

fs.promises是 Node.jsfs模块提供的Promise 化文件系统 API,替代了传统的回调式fs方法,天然适配async/await语法,是现代 Node.js 开发中处理文件系统的首选方式。

一、核心基础

1. 兼容性

  • Node.js v10.0.0 起,fs.promises被标记为稳定版;
  • Node.js v14.0.0 起,支持import fs from 'fs/promises'(更简洁的导入方式)。

2. ESM 配置前提

使用 ESM 格式(import/export)需满足以下任一条件:

  • 将文件后缀改为.mjs
  • 在项目根目录的package.json中添加"type": "module"

3. 导入方式

推荐使用更简洁的方式(Node.js 14+):

// 推荐:直接导入 promises 模块importfsfrom'fs/promises';// 配合路径处理(ESM 内置模块)importpathfrom'path';

兼容更低版本(Node.js 10+):

import{promisesasfs}from'fs';importpathfrom'path';

二、核心方法 & 代码示例

(一)文件基础操作

1. 读取文件(fs.readFile)

读取文件内容,支持文本/二进制格式,参数说明:

  • path:文件路径(推荐用path.resolve处理);
  • options:可选,包含encoding(编码,如utf8)、flag(操作模式,如r只读)。

示例1:读取文本文件

asyncfunctionreadTextFile(){// 绝对路径(避免相对路径陷阱)constfilePath=path.resolve(__dirname,'example.txt');try{constcontent=awaitfs.readFile(filePath,{encoding:'utf8',// 文本编码,省略则返回 Bufferflag:'r'// 只读模式(默认)});console.log('文件内容:\n',content);}catch(err){console.error('读取失败:',err.message);}}readTextFile();

示例2:读取二进制文件(图片/视频)

asyncfunctionreadBinaryFile(){constimgPath=path.resolve(__dirname,'image.png');try{// 不指定 encoding,返回 Bufferconstbuffer=awaitfs.readFile(imgPath);console.log('文件大小:',buffer.length,'字节');// 可直接写入新文件(复制二进制文件)awaitfs.writeFile(path.resolve(__dirname,'copy-image.png'),buffer);}catch(err){console.error('读取二进制文件失败:',err.message);}}readBinaryFile();
2. 写入文件(fs.writeFile)

写入内容到文件,默认覆盖原有内容,参数说明:

  • path:目标文件路径;
  • data:写入内容(字符串/Buffer/Uint8Array);
  • options:可选,包含encodingflagw覆盖、a追加、wx原子写入(文件存在则失败))、mode(文件权限,如0o644)。

示例:写入/追加文件

asyncfunctionwriteFileExample(){constfilePath=path.resolve(__dirname,'output.txt');constcontent=`Hello fs.promises! 当前时间:${newDate().toISOString()}`;try{// 1. 覆盖写入(默认 flag: 'w')awaitfs.writeFile(filePath,content,{encoding:'utf8',mode:0o644// 权限:所有者读写,其他只读});console.log('覆盖写入成功');// 2. 追加内容(两种方式)awaitfs.appendFile(filePath,'\n这是追加的内容',{encoding:'utf8'});// 或用 writeFile + flag: 'a'// await fs.writeFile(filePath, '\n另一种追加方式', { flag: 'a' });}catch(err){console.error('写入失败:',err.message);}}writeFileExample();
3. 复制文件(fs.copyFile)

复制文件,支持原子操作,参数:

  • src:源文件路径;
  • dest:目标文件路径;
  • mode:可选,如fs.constants.COPYFILE_EXCL(目标存在则报错)。
asyncfunctioncopyFileExample(){constsrc=path.resolve(__dirname,'source.txt');constdest=path.resolve(__dirname,'target.txt');try{// 基础复制(目标存在则覆盖)awaitfs.copyFile(src,dest);console.log('文件复制成功');// 原子复制(目标存在则报错)// await fs.copyFile(src, dest, fs.constants.COPYFILE_EXCL);}catch(err){console.error('复制失败:',err.message);}}copyFileExample();
4. 重命名/移动文件(fs.rename)

既可以重命名文件,也可以移动文件(跨目录)。

asyncfunctionrenameFileExample(){constoldPath=path.resolve(__dirname,'old-name.txt');constnewPath=path.resolve(__dirname,'new-name.txt');// 移动到子目录constmovePath=path.resolve(__dirname,'subdir/new-name.txt');try{// 1. 重命名awaitfs.rename(oldPath,newPath);console.log('重命名成功');// 2. 移动(需确保子目录存在)awaitfs.mkdir(path.dirname(movePath),{recursive:true});awaitfs.rename(newPath,movePath);console.log('移动文件成功');}catch(err){console.error('重命名/移动失败:',err.message);}}renameFileExample();
5. 删除文件(fs.unlink / fs.rm)
  • fs.unlink:传统删除文件方法;
  • fs.rm(Node.js 14+):更通用,支持文件/目录,推荐使用。
asyncfunctiondeleteFileExample(){constfilePath=path.resolve(__dirname,'to-delete.txt');try{// 推荐:fs.rm(force: true 避免文件不存在时报错)awaitfs.rm(filePath,{force:true});console.log('文件删除成功');// 传统方式:fs.unlink// await fs.unlink(filePath);}catch(err){console.error('删除失败:',err.message);}}deleteFileExample();
6. 获取文件信息(fs.stat / fs.lstat)
  • fs.stat:获取文件/目录信息;
  • fs.lstat:区分符号链接(返回链接本身信息,而非目标文件)。
asyncfunctiongetFileStat(){constfilePath=path.resolve(__dirname,'example.txt');try{conststats=awaitfs.stat(filePath);console.log('文件信息:',{isFile:stats.isFile(),// 是否是文件isDirectory:stats.isDirectory(),// 是否是目录size:stats.size,// 大小(字节)birthtime:stats.birthtime,// 创建时间mtime:stats.mtime// 修改时间});}catch(err){console.error('获取文件信息失败:',err.message);}}getFileStat();

(二)目录操作

1. 创建目录(fs.mkdir)

支持创建多级目录(recursive: true)。

asyncfunctioncreateDirExample(){// 多级目录constdirPath=path.resolve(__dirname,'new-dir/sub-dir/child-dir');try{awaitfs.mkdir(dirPath,{recursive:true,// 自动创建不存在的父目录mode:0o755// 目录权限:所有者读写执行,其他读执行});console.log('多级目录创建成功');}catch(err){console.error('创建目录失败:',err.message);}}createDirExample();
2. 读取目录(fs.readdir)

读取目录下的文件/子目录,withFileTypes: true可获取文件类型信息。

asyncfunctionreadDirExample(){constdirPath=path.resolve(__dirname,'new-dir');try{// withFileTypes: true 返回 Dirent 对象(包含类型信息)constdirents=awaitfs.readdir(dirPath,{withFileTypes:true});dirents.forEach(dirent=>{consttype=dirent.isFile()?'文件':dirent.isDirectory()?'目录':'其他';console.log(`名称:${dirent.name},类型:${type}`);});}catch(err){console.error('读取目录失败:',err.message);}}readDirExample();
3. 删除目录(fs.rmdir / fs.rm)
  • fs.rmdir:传统删除目录(需空目录,Node.js 12+ 支持recursive: true删除非空);
  • fs.rm(Node.js 14+):推荐,支持递归删除非空目录。
asyncfunctiondeleteDirExample(){constdirPath=path.resolve(__dirname,'new-dir');try{// 推荐:fs.rm 递归删除(force: true 避免目录不存在时报错)awaitfs.rm(dirPath,{recursive:true,force:true});console.log('目录删除成功');// 传统方式:fs.rmdir(需 recursive: true)// await fs.rmdir(dirPath, { recursive: true });}catch(err){console.error('删除目录失败:',err.message);}}deleteDirExample();

(三)其他常用方法

1. 检查文件可访问性(fs.access)

验证文件/目录的权限(读/写/执行)或是否存在。

asyncfunctioncheckAccessExample(){constfilePath=path.resolve(__dirname,'example.txt');try{// 检查是否存在(fs.constants.F_OK)awaitfs.access(filePath,fs.constants.F_OK);console.log('文件存在');// 检查是否可读(fs.constants.R_OK)awaitfs.access(filePath,fs.constants.R_OK);console.log('文件可读');// 检查是否可写(fs.constants.W_OK)awaitfs.access(filePath,fs.constants.W_OK);console.log('文件可写');}catch(err){console.error('访问检查失败:',err.message);}}checkAccessExample();
2. 符号链接操作(fs.symlink / fs.readlink)
asyncfunctionsymlinkExample(){consttarget=path.resolve(__dirname,'example.txt');// 目标文件constlinkPath=path.resolve(__dirname,'example-link.txt');// 链接文件try{// 创建符号链接awaitfs.symlink(target,linkPath);console.log('符号链接创建成功');// 读取链接指向的路径constrealPath=awaitfs.readlink(linkPath);console.log('链接指向:',realPath);}catch(err){console.error('符号链接操作失败:',err.message);}}symlinkExample();

三、错误处理

fs.promises所有方法返回的 Promise 失败时会抛出错误,需用try/catch捕获,常见错误码:

错误码含义
ENOENT文件/目录不存在
EACCES权限不足
EEXIST文件/目录已存在(原子操作时)
EPERM操作不被系统允许
EISDIR操作对象是目录(但方法要求文件)

示例:针对性错误处理

asyncfunctionerrorHandlingExample(){constfilePath=path.resolve(__dirname,'non-existent.txt');try{awaitfs.readFile(filePath,'utf8');}catch(err){switch(err.code){case'ENOENT':console.error('错误:文件不存在');break;case'EACCES':console.error('错误:无读取权限');break;default:console.error('未知错误:',err.message);}}}errorHandlingExample();

四、关键注意事项

1. ESM 中 __dirname/__filename 替代

ESM 中没有__dirname/__filename,需手动实现:

import{fileURLToPath}from'url';import{dirname}from'path';const__filename=fileURLToPath(import.meta.url);// 当前文件路径const__dirname=dirname(__filename);// 当前文件目录

2. 大文件处理

fs.readFile/fs.writeFile会将整个文件加载到内存,大文件(>100MB)推荐使用流

import{createReadStream,createWriteStream}from'fs';import{pipeline}from'stream/promises';// 流的 Promise 化 APIasyncfunctionstreamLargeFile(){constsrc=path.resolve(__dirname,'large-file.txt');constdest=path.resolve(__dirname,'copy-large-file.txt');try{// 流式复制大文件awaitpipeline(createReadStream(src),createWriteStream(dest));console.log('大文件复制成功');}catch(err){console.error('大文件处理失败:',err.message);}}streamLargeFile();

3. 批量操作优化

批量处理文件时,用Promise.all并行执行(注意系统文件描述符限制):

asyncfunctionbatchReadFiles(){constfiles=['file1.txt','file2.txt','file3.txt'].map(f=>path.resolve(__dirname,f));try{// 并行读取(失败时捕获单个错误,不阻塞整体)constresults=awaitPromise.all(files.map(file=>fs.readFile(file,'utf8').catch(err=>({file,error:err.message}))));results.forEach((res,idx)=>{if(res.error){console.error(`读取${files[idx]}失败:`,res.error);}else{console.log(`读取${files[idx]}成功:`,res.substring(0,50)+'...');}});}catch(err){console.error('批量操作异常:',err.message);}}batchReadFiles();

4. 原子操作

使用flag参数实现原子写入(避免并发覆盖):

  • wx:写入文件,若文件已存在则失败;
  • ax:追加内容,若文件不存在则失败。
asyncfunctionatomicWrite(){constfilePath=path.resolve(__dirname,'atomic.txt');try{awaitfs.writeFile(filePath,'原子写入内容',{flag:'wx'});console.log('原子写入成功');}catch(err){if(err.code==='EEXIST'){console.error('文件已存在,原子写入失败(避免覆盖)');}}}atomicWrite();

五、总结

fs.promises是 Node.js 处理文件系统的现代方案,核心优势:

  1. 摆脱回调地狱,代码更易读、易维护;
  2. 适配async/await,错误处理更清晰;
  3. API 语义化,与传统fs方法一一对应,学习成本低。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/17 18:15:38

超轻量OCR如何重塑工业智能化?5大应用场景深度解析

超轻量OCR如何重塑工业智能化?5大应用场景深度解析 【免费下载链接】chineseocr_lite 超轻量级中文ocr,支持竖排文字识别, 支持ncnn、mnn、tnn推理 ( dbnet(1.8M) crnn(2.5M) anglenet(378KB)) 总模型仅4.7M 项目地址: https://gitcode.com/gh_mirr…

作者头像 李华
网站建设 2026/4/18 8:54:48

传统康复 vs 智能 Agent 指导:3项核心指标全面碾压,你知道吗?

第一章:医疗康复 Agent 的运动指导在现代智能医疗系统中,医疗康复 Agent 作为连接患者与专业治疗方案的桥梁,正逐步实现个性化、实时化的运动康复指导。这类 Agent 借助传感器数据、动作识别算法和自然语言交互能力,为用户提供精准…

作者头像 李华
网站建设 2026/4/18 8:32:10

2025 LangChain智能体工程年度报告发布!

看完这份LangChain年度报告,我感觉现在的AI圈已经从“赛博吹水”进化到“撸起袖子干实事”的阶段了。别看大佬们还在吵AGI什么时候来,打工人已经偷偷用Agent把活儿干完了。 AI智能体2026:从画饼到吃饼 重点中的重点:现在的Agent到…

作者头像 李华
网站建设 2026/4/16 14:55:55

MaterialDesignInXamlToolkit终极指南:30分钟打造现代化WPF应用

MaterialDesignInXamlToolkit终极指南:30分钟打造现代化WPF应用 【免费下载链接】MaterialDesignInXamlToolkit Googles Material Design in XAML & WPF, for C# & VB.Net. 项目地址: https://gitcode.com/gh_mirrors/ma/MaterialDesignInXamlToolkit …

作者头像 李华
网站建设 2026/4/18 3:37:36

终极指南:快速搭建Flutter企业级后台管理系统

终极指南:快速搭建Flutter企业级后台管理系统 【免费下载链接】flutter_admin Flutter Admin: 一个基于 Flutter 的后台管理系统、开发模板。A backend management system and development template based on Flutter 项目地址: https://gitcode.com/gh_mirrors/f…

作者头像 李华