跳到主要内容

3.2-fs和path模块

Create by fall on 04 Nov 2020 Recently revised in 13 Mar 2024

fs 模块

对于文件或者文件夹的操作通过 fs 模块进行操作,对于文件路径的操作通过 path 模块实现。

文件夹操作

创建文件夹的完整示例

const fs = require('fs')
// fs.makedir(path[,mode],callback)
// mode 为目录的权限,默认是 777
fs.mkdir('./active', (err) => {
if (err) {
console.log(err);
return
} else {
console.log('文件夹创建成功'); // 就这几行代码就可以实现,对于文件夹的创建。
}
})

修改文件夹名称

const fs = require('fs')
var dirName = './active'
fs.rename(dirName,'./别介啊',(err)=>{
if (err) {
console.log(err);
return
} else {
console.log('名称修改完成');
}
})

删除文件夹

fs.rmdir('./别介啊',(err)=>{
if(err){
console.log("移除出现问题");
console.log(err);
}else{
console.log("移出成功");
}
})

因为必须删除文件夹内的所有文件,才能删除文件夹,此时如果想要一次性删除文件夹和里面的内容,需要依次删除文件,然后删除文件夹。也可以使用库直接实现,参看最删除文件夹

文件的操作

文件系统的标志

  • a 打开文件进行追加。如果文件不存在则创建文件。
  • a+ 打开文件用于读取和追加。如果文件不存在则创建文件。
  • as 同步模式追加文件,as+ 同步模式,读取 或者追加文件
  • r 打开文件用于读取,如果不存在,会产生异常
  • r+ 打开文件用于读写,如果不存在,会产生异常。
  • rs+ 以同步的方式打开文件进行读写,指示操作系统绕过本地文件系统缓存。
  • w 打开文件进行写入,创建(不存在时)或是截断(存在该文件)
  • w+ 打开文件用于读写,如果文件不存在则创建文件。

aa+ww+、添加 x 后,如果路径存在则失败,其他都相同

const fs = requrie('fs')
// fs.open(path,flags[,mode],callback)
fs.open('./package.json','a','777',()=>{
// 回调函数
})

写入文件

主要使用格式 fs.writeFile(file, data[, options], callback)

// 写入文件
var fs = require('fs');
fs.writeFile('./hello.txt',msg,'utf8',function(err){
if(err){
console.log('写入文件出错:'+ err);
}else{
console.log('writen successful');
}
})
fs.writeFile('/Users/joe/test.txt', content, { flag: 'a+' }, err => {})

追加文件可以直接通过

fs.appendFile('fileName',content,'utf-8',err=>{})

读取文件

书写格式:fs.readFile(path[, options], callback)

var fs = require('fs');
// 读取文件
fs.readFile('./hello.txt','utf8',function(err,data){
if(err){
throw err;
}
console.log(data);
})

剪切文件

剪切文件的方式,其实就是重命名文件名称

fs.rename('file.js', 'node_modules/file.js', (err) => {
if(err) {
console.log(err);
return false;
} else {
console.log("剪切成功!");
}
})

关闭文件

常用的方法

文件的常用方法

fd 为通过 fs.open() 方法返回的文件描述符

方法名称方法功能
fs.open()打开文件
fs.writeFile()写入文件
fs.read()参数分别为(fd, buffer, offset, length, position, callback)
fs.appendFile()对文件进行数据追加,如果没有文件,创建并写入
fs.chmod()更改文件权限
fs.lchmod()
fs.close()关闭文件
fs.unlink()删除文件,参数 path,callback
fs.ftruncate()截取文件 fd,len,callback

文件夹的常用方法

  • mode 表示权限
  • path 表示路径
方法名称方法功能
fs.mkdir()创建目录,参数(path[,mode],callback
fs.readdir()读取目录,参数(path,callback
fs.rmdir()删除目录,参数(path,callback

文件的操作中,围绕着文件的权限。

如果有读,写,执行,这三个权限,二进制中这些权限就表示为 111。十进制中表示为 7。

当然不同身份的用户可以进行权限设置:自己,组内用户,一般用户的权限可以分别进行设置,777,表示三个用户都有读,写,执行的权限。

IO 机制

你要拷贝一个 20G 大的文件,如果你一次性将 20G 的数据读入到内存,你的内存条可能不够用, 或者严重影响性能. 但是你如果使用一个 1MB 大小的缓存 (buf) 每次读取 1Mb, 然后写入 1Mb, 那么不论这个文件多大都只会占用 1Mb 的内存。

而在 Node.js 中, 原理与上述 C 代码类似,不过在读写的实现上通过 libuv 与 EventEmitter 加上了异步的特性。在 linux/unix 中你可以通过 | 来感受到流式操作

JavaScript 语言自身只有字符串数据类型,没有二进制数据类型。

但在处理像TCP流或文件流时,必须使用到二进制数据。因此在 Node.js中,定义了一个 Buffer 类,该类用来创建一个专门存放二进制数据的缓存区。

在 Node.js 中,Buffer 类是随 Node 内核一起发布的核心库。Buffer 库为 Node.js 带来了一种存储原始数据的方法,可以让 Node.js 处理二进制数据,每当需要在 Node.js 中处理I/O操作中移动的数据时,就有可能使用 Buffer 库。原始数据存储在 Buffer 类的实例中。一个 Buffer 类似于一个整数数组,但它对应于 V8 堆内存之外的一块原始内存。

path

相对于当前执行文件时的路径,而不是该文件的目标路径

解决方法

  • __dirname 当前 .js 文件所在的目录

  • __filename __dirname + 当前文件名

这两个变量并不是全局使用的,只不过是执行文件时有个沙箱,沙箱提供了该功能

由于 linuxwindowsMacOS 使用不同的路径解析方式,因此会使用 path 中的 join 进行拼接。

const path = require('path')
path.join(__dirname,'hello.txt')

文件操作时,无需判断文件是否存在,直接进行操作,如果不存在会反映在 error 对象中

module

如果使用了 ES6 的语法,需要一些特殊方法去获取当前目录和拼接

import { resolve as pathResolve } from 'path'
import { fileURLToPath } from 'node:url'
const __dirname = fileURLToPath(new URL('.', import.meta.url))
pathResolve(__dirname, 'hello.txt')

其它操作

删除文件夹

插件安装npm i fs-extra

const fs = require('fs-extra')
const folder = '/Users/joe'
fs.remove(folder, err => {
console.error(err)
})

同步执行代码

const fs = require('fs')
// 第一种方法:将 fs.readFile 同步化
const {promisify} = require('util')
const readFile = promisify(fs.readFile)
readFile('./package.json','utf-8').then(res=>{
console.log(res);
})

// 第二种方法:直接使用同步方法
const {promises} = require('fs')
promises.readFile('./package.json','utf-8').then(data=>{
console.log(data)
})

// 第三种方法:使用同步后的方法,进行 generator
const {promisify} = require('util')
const readFile = promisify(fs.readFile)
function* read(){
yield readFile('./package.json')
}
let generate = read()
generate.next().value.then(data=>{
console.log(data);
})

// 第四种方法
const {promisify} = require('util')
// const readFile = promisify(fs.readFile)
async function outFile(){
let a = await fs.readFileSync('./package.json')
console.log(a)
}
outFile()

文件流

管道流,链式流

管道流就像是把一个文件和另一个文件连接起来,传送数据

链式流,就像是一个文件,先做操作一,在做操作二,再做操作三

流,就像是文件的操作,把文件慢慢的从一个点,流向另一个点,从而实现复制(一般用于大文件的复制)。

const fs = require('fs')
const readerStream = fs.createReadStream('./package.json')
const writerStream = fs.createWriteStream('./test.txt')
readStream.pipe(writeStream)
console.log("执行完成")

zlib 模块,用来处理压缩的功能。

const fs = require('fs')
const zlib = requrie('zlib')
fs.createReadStream('./test.txt').pipe(zlib.createGzip()).pipe(fs.createWriteStream('test.zip'));
// 先压缩文件,然后将文件导出。
console.log('文件压缩成功');