引言:为什么在 JavaScript 中处理文件是必备技能
\n\n想象一下,您是一艘宇宙飞船的船长。您的任务是管理货舱、氧气储备和航行日志。在 Web 开发的世界中,文件系统就是那些货舱,而 JavaScript 就是您的控制台。如果不掌握文件操作,您将滞留在轨道上:无法保存用户设置、无法加载服务器配置、也无法处理日志文件。
\n\n许多新手认为 JavaScript 只存在于浏览器中,无法触及磁盘上的文件。这是一个误区!随着 Node.js 的出现(甚至在现代浏览器中通过 File API),JavaScript 已成为处理文件系统的完整工具。今天,我们将详细讲解如何读取、写入、删除和移动文件,以及如何避免异步陷阱。
\n\n顺便提一下,如果您刚刚开始编程之旅,建议先学习 JavaScript 基础知识——这将帮助您更快地理解下面的示例。
\n\nJavaScript 在哪里处理文件?两个世界——两种方法
\n\n在深入代码之前,让我们明确一点:JS 中的文件操作分为两大阵营。
\n\n1. 服务器端 JavaScript (Node.js)
\n在这里,我们可以完全访问文件系统:创建、删除、重命名、流式读取——应有尽有。通过内置模块 fs (File System) 进行操作。它就像一把处理文件的瑞士军刀。
2. 客户端 JavaScript (浏览器)
\n浏览器是一个带有诸多限制的“沙盒”。您不能随意读取用户计算机上的任何文件(否则黑客们就要庆祝了)。但您可以处理用户通过 <input type="file"> 自行选择的文件,或者通过 FileReader 和 Blob API 进行操作。
本文将重点介绍 Node.js,但在最后会提供一个浏览器示例作为额外内容。
\n\nfs 模块:您的主要工具
\n\n在 Node.js 中,文件操作从引入 fs 模块开始:
const fs = require('fs'); // 旧风格\n// 或\nimport fs from 'fs'; // 如果使用 ES 模块\n\nfs 有三种工作模式:同步、基于回调的异步和基于 Promise 的异步。我们将使用最后一种——配合 async/await,因为这是现代且可读性高的方式。
读取文件:从简单到复杂
\n\n假设我们有一个包含文本的文件 data.txt。最简单的读取方式如下:
import { readFile } from 'fs/promises';\n\nasync function readMyFile() {\n try {\n const data = await readFile('data.txt', 'utf-8');\n console.log(data);\n } catch (err) {\n console.error('读取错误:', err.message);\n }\n}\n\nreadMyFile();\n\n这里重要的是什么?'utf-8' 是编码。如果不指定,您将得到一个原始缓冲区 (Buffer),需要将其转换为字符串。对于文本文件,请始终指定编码。
如果文件很大(例如,500 MB 的日志文件),一次性读取整个文件是个坏主意。这时就需要流 (streams) 来帮忙:
\n\nimport { createReadStream } from 'fs';\nimport { createInterface } from 'readline';\n\nasync function readLargeFile() {\n const stream = createReadStream('bigfile.log', 'utf-8');\n const rl = createInterface({ input: stream });\n\n for await (const line of rl) {\n console.log('行:', line);\n // 在读取过程中逐行处理\n }\n}\n\nreadLargeFile();\n\n写入文件:创建和追加
\n\n写入有两种类型:覆盖写入 (write) 和追加写入 (append)。区别很明显:write 会覆盖旧文件,append 会在末尾添加内容。
import { writeFile, appendFile } from 'fs/promises';\n\n//