Node.js教程:新手入门
3,文件操作
### 3.1 Node.js 文件统计信息 - 使用 [`fs` 模块](https://dev.nodejs.cn/api/fs/) 提供的 `stat()` 方法可以获得文件详细信息,stat()调用你传递的回调函数,带有 2 个参数: 错误消息和文件统计信息 ```typescript const fs = require('fs'); fs.stat('/Users/joe/test.txt', (err, stats) => { if (err) { console.error(err); } // we have access to the file stats in `stats` }); ``` - Node.js 还提供了一个 sync 方法,它会阻塞线程直到文件统计信息准备就绪: ```typescript const fs = require('fs'); try { const stats = fs.statSync('/Users/joe/test.txt'); } catch (err) { console.error(err); } ``` - stats 变量中提供的信息 1. 如果文件是目录或文件,则使用 `stats.isFile()` 和 `stats.isDirectory()` 2. 如果文件是使用 `stats.isSymbolicLink()` 的符号链接 3. 使用 `stats.size` 以字节为单位的文件大小。 ### 3.2 Node.js 文件路径 > 系统中的每个文件都有一个路径。 在 Linux 、 macOS 、window中路径不尽相同,在应用中使用路径时需要注意,因为必须考虑到这种差异。 > > 你使用 `const path = require('path');` 将此模块包含在你的文件中,然后你可以开始使用它的方法。 ```typescript const notes = '/users/joe/notes.txt'; path.dirname(notes); // /users/joe 获取文件的父文件夹 path.basename(notes); // notes.txt 获取文件名部分 path.extname(notes); // .txt 获取文件扩展名 path.basename(notes, path.extname(notes)); // notes 指定第二个参数来获取不带扩展名的文件名 ``` - `path.join()` 连接路径的两个或多个部分 ```typescript const name = 'joe'; path.join('/', 'users', name, 'notes.txt'); // '/users/joe/notes.txt' ``` - `path.resolve()` 获取相对路径的绝对路径计算 ```js //将 /joe.txt 附加到当前工作目录 path.resolve('joe.txt'); // '/Users/joe/joe.txt' // 如果指定第二个参数文件夹,resolve 将使用第一个作为第二个的基础 path.resolve('tmp', 'joe.txt'); // '/Users/joe/tmp/joe.txt' //如果第一个参数以斜杠开头,则表示它是绝对路径 path.resolve('/etc', 'joe.txt'); // '/etc/joe.txt' ``` - `path.normalize()` 当它包含诸如 `.` 或 `..` 或双斜线的相对说明符时,它将尝试计算实际路径: ```js path.normalize('/users/joe/..//test.txt'); // '/users/test.txt' ``` > **resolve 和 normalize 都不会检查路径是否存在**. 他们只是根据他们得到的信息计算出一条路径。 ### 3.3 在 Node.js 中使用文件描述符 > 文件描述符是对打开文件的引用,是使用 `fs` 模块提供的 `open()` 方法打开文件时返回的数字 (fd)。 此编号 (`fd`) 唯一标识操作系统中打开的文件 ```js const fs = require('fs'); fs.open('/Users/joe/test.txt', 'r', (err, fd) => { // fd is our file descriptor }); //fs.openSync 方法打开文件,该方法返回文件描述符,而不是在回调中提供它 const fd = fs.openSync('/Users/joe/test.txt', 'r'); ``` **你将常用的其他标志是:** | 标志 | 描述 | 如果文件不存在则创建文件 | | :--- | :----------------------------------------------------------- | :----------------------- | | `r+` | 此标志打开文件**读取** 和**写入** | ❌ | | `w+` | 此标志打开文件**读取** 和**写入** 它还将流定位在**开始** 文件的 | ✅ | | `a` | 此标志打开文件**写入** 它还将流定位在**结尾** 文件的 | ✅ | | `a+` | 此标志打开文件**读取** 和**写入** 它还将流定位在**结尾** 文件的 | ✅ | - `fs/promises` 模块 ```js const fs = require('fs/promises'); async function example() { let filehandle; try { filehandle = await fs.open('/Users/joe/test.txt', 'r'); console.log(filehandle.fd); console.log(await filehandle.readFile({ encoding: 'utf8' })); } finally { if (filehandle) await filehandle.close(); } } example(); ``` ### 3.4 使用 Node.js 读取文件 > `fs.readFile()`、`fs.readFileSync()`、`fsPromises.readFile()` 这三个都在返回数据前读取了内存中文件的全部内容。这意味着大文件将对你的内存消耗和程序执行速度产生重大影响。在这种情况下,更好的选择是使用流读取文件内容。 ```js const fs = require('fs'); fs.readFile('/Users/joe/test.txt', 'utf8', (err, data) => { if (err) { console.error(err); return; } console.log(data); }); //同步版本 fs.readFileSync() const data = fs.readFileSync('/Users/joe/test.txt', 'utf8'); ``` - 使用 `fs/promises` 模块提供的基于 promise 的 `fsPromises.readFile()` 方法: ```js jscopyconst fs = require('fs/promises'); async function example() { try { const data = await fs.readFile('/Users/joe/test.txt', { encoding: 'utf8' }); console.log(data); } catch (err) { console.log(err); } } example(); ``` ### 3.5 使用 Node.js 写入文件 ```js const fs = require('fs'); const content = 'Some content!'; fs.writeFile('/Users/joe/test.txt', content, err => { if (err) { console.error(err); } }); //同步地写入文件 try { fs.writeFileSync('/Users/joe/test.txt', content); } catch (err) { console.error(err); } ``` - 使用 `fs/promises` 模块提供的基于 promise 的 `fsPromises.writeFile()` 方法: ```js jscopyconst fs = require('fs/promises'); async function example() { try { const content = 'Some content!'; await fs.writeFile('/Users/joe/test.txt', content); } catch (err) { console.log(err); } } example(); ``` - **通过指定标志来修改默认值** ```js fs.writeFile('/Users/joe/test.txt', content, { flag: 'a+' }, err => {}); ``` - **将内容附加到文件** ```js const fs = require('fs'); const content = 'Some content!'; fs.appendFile('file.log', content, err => { if (err) { console.error(err); } // done! }); //fsPromises.appendFile() const fs = require('fs/promises'); async function example() { try { const content = 'Some content!'; await fs.appendFile('/Users/joe/test.txt', content); } catch (err) { console.log(err); } } example(); ``` ### 3.6 在 Node.js 中使用文件夹 - `fs.access()`:检查文件夹是否存在以及 Node.js 是否可以使用其权限访问它 - `fs.mkdir() 或 fs.mkdirSync() 或 fsPromises.mkdir()`:新建一个文件夹 ```typescript jscopyconst fs = require('fs'); const folderName = '/Users/joe/test'; try { if (!fs.existsSync(folderName)) { //检查文件夹是否存在 fs.mkdirSync(folderName); //同步创建文件夹 } } catch (err) { console.error(err); } ``` - `fs.readdir()` 或 `fs.readdirSync()` 或 `fsPromises.readdir()`: 读取目录的内容 ```typescript //读取文件夹的内容,包括文件和子文件夹,并返回它们的相对路径 fs.readdirSync(folderPath); //获得完整路径 fs.readdirSync(folderPath).map(fileName => { return path.join(folderPath, fileName); }); //可以过滤结果以仅返回文件,并排除文件夹: const isFile = fileName => { return fs.lstatSync(fileName).isFile(); }; fs.readdirSync(folderPath) .map(fileName => { return path.join(folderPath, fileName); }) .filter(isFile); ``` - `fs.rename()` 或 `fs.renameSync()` 或 `fsPromises.rename()` :重命名文件夹 ```typescript // 重命名文件夹 第一个参数是当前路径,第二个是新路径 fs.renameSync('/Users/joe', '/Users/roger'); fs.rename('/Users/joe', '/Users/roger', err => { if (err) { console.error(err); } // done }); ``` - `fs.rmdir()` 或 `fs.rmdirSync()` 或 `fsPromises.rmdir()`: 删除文件夹 ```typescript fs.rmdir(dir, err => { if (err) { throw err; } console.log(`${dir} is deleted!`); }); //递归删除文件夹以及里面的内容 ,忽略异常 fs.rm(dir, { recursive: true, force: true }, err => { if (err) { throw err; } console.log(`${dir} is deleted!`); }); ```
顶部
收展
底部
[TOC]
目录
1,新手入门
2,异步工作
3,文件操作
4,命令行
5,yarn 依赖管理
相关推荐
Node.js接口
Node.js:ExpressWeb
朴灵《深入浅出 Node.js》