使用node fs读写文件


1.fs.open() 读取/写入文件

介绍: 要创建文件,写入文件或读取文件,使用fs.open()方法。 fs.readFile()仅用于读取文件,类似地,fs.writeFile()仅用于写入文件,而fs.open()方法对文件进行多项操作。
首先,我们需要加载fs 类,该类是用于访问物理文件系统的模块。为此,使用了require方法。例如:
var fs = require('fs');

用法:

fs.open(filename, flags, mode, callback);

参数:此方法接受上述和以下所述的四个参数:

  • filename:必选参数,文件名。

  • flag:操作标识,必须在其中打开文件的操作,见下文表格。

  • mode:设置文件的模式,即 r-read,w-write,r + -readwrite。它将默认设置为读写。

  • callback
    这是在读取文件后调用的回调函数。它带有两个参数:

    • err:如果发生任何错误。
    • fd:为一个整数,表示打开文件返回的文件描述符,window 中又称文件句柄

所有flag类型的标志描述如下:

flag 描述
r 打开文件以读取文件并在文件不存在时引发异常。
r+ 打开文件进行读写。如果文件不存在,则引发异常。
rs+ 以同步模式打开文件以进行读写。
w 打开文件进行写入。如果文件不存在,则会创建该文件。
wx 与“ w”相同,但如果存在路径则失败。
w+ 打开文件进行读写。如果文件不存在,则会创建该文件。
wx+ 与“ w +”相同,但如果存在路径则失败。
a 打开要追加的文件。如果文件不存在,则会创建该文件。
ax 与“ a”相同,但如果存在路径则失败。
a+ 打开文件以进行读取和追加。如果文件不存在,则会创建该文件。
ax+ 与“ a +”相同,但如果存在路径则失败。

完整示例:

fs.open(__dirname + "/test.txt", "r", "0666", function (err, fd) {
    console.log(fd);
});

console.log("Open file!");

// To open file in write and read mode,
// create file if doesn't exists.
fs.open("demo.txt", "w+", function (err, f) {
    if (err) {
        return console.error(err);
    }
    console.log(f);
    console.log("File opened!!");
});

2.fs.readFile() 读取文件

fs.readFile()方法是一种内置方法,用于读取文件。此方法将整个文件读入缓冲区

用法:

fs.readFile(filename, [options], callback);

参数:此方法接受上述和以下所述的三个参数:

  • filename:必选参数,文件名。
  • options:可选参数,可指定 flag(文件操作选项,如 r+ 读写;w+ 读写,文件不存在则创建)及 encoding 属性
  • callback:读取文件后的回调函数,参数默认第一个err,第二个data数据

返回值:它返回存储在文件中的内容/数据或错误(如果有)。

完整示例:

fs.readFile(__dirname + "/test.txt", { flag: "r+", encoding: "utf8" }, function (err, data) {
    if (err) {
        console.error(err);
        return;
    }
    console.log(data);
});

3.fs.writeFile() 写入文件

fs.writeFile()方法用于将指定的数据异步写入文件。默认情况下,文件将被替换(如果存在)。

用法:

fs.writeFile(filename, data, [options], callback);

参数:此方法接受上述和以下所述的四个参数:

  • filename:必选参数,文件名。
  • data:写入的数据,可以字符或一个BufferTypedArrayDataView对象。
  • options:它是一个字符串或对象,可用于指定将影响输出的可选参数。它具有三个可选参数:
    • encoding:它是一个字符串,它指定文件的编码。默认值为”utf8”。
    • mode:它是一个整数,指定文件模式。默认值为”0o666”。
    • flag:它是一个字符串,它指定附加到文件时使用的标志。默认值为”a”。
  • callback:读取文件后的回调函数,参数默认第一个err,第二个data数据

完整示例:

fs.writeFile(__dirname + "/test.txt", w_data, { flag: "a" }, function (err) {
    if (err) {
        console.error(err);
    } else {
        console.log("写入成功");
    }
});

4.fs.appendFile() 以追加方式写文件

fs.appendFile()方法用于将给定数据异步附加到文件中。如果不存在,则创建一个新文件。

用法:

fs.appendFile(filename, data, [options], callback);

参数:此方法接受上述和以下所述的四个参数:

  • filename:它是一个字符串,缓冲区,URL 或数字,表示将附加到其后的源文件名或文件描述符。
  • data:它是一个字符串或缓冲区,表示必须附加的数据。
  • options:它是一个字符串或对象,可用于指定将影响输出的可选参数。它具有三个可选参数:
    • encoding:它是一个字符串,它指定文件的编码。默认值为”utf8”。
    • mode:它是一个整数,指定文件模式。默认值为”0o666”。
    • flag:它是一个字符串,它指定附加到文件时使用的标志。默认值为”a”。
  • callback:该方法执行时将调用该函数。
    • err:如果方法失败,将引发错误。

完整示例:

fs.appendFile(__dirname + "/test.txt", "使用fs.appendFile追加文件内容", function () {
    console.log("追加内容完成");
    if (err) {
        console.log(err);
    } else {
        // Get the file contents after the append operation
        console.log("\nFile Contents of file after append:", fs.readFileSync("example_file.txt", "utf8"));
    }
});

5.fs.read() 读取打开的文件内容到缓冲区中

用法:

fs.read(fd, buffer, offset, length, position, callback);

参数:此方法接受上述和以下所述的六个参数:

  • fd:使用 fs.open 打开成功后返回的文件描述符。
  • buffer:一个 Buffer 对象,v8 引擎分配的一段内存。
  • offset:整数,向缓存区中写入时的初始位置,以字节为单位。
  • length:整数,读取文件的长度。
  • position:整数,读取文件初始位置;文件大小以字节为单位。如果 position 为 null,则从当前文件位置读取数据。
  • callback(err, bytesRead, buffer):读取执行完成后回调函数,bytesRead实际读取字节数,被读取的缓存区对象

完整示例:

fs.open(__dirname + "/test.txt", "r", function (err, fd) {
    if (err) {
        console.error(err);
        return;
    } else {
        var buffer = new Buffer(255);
        console.log(buffer.length);
        //每一个汉字utf8编码是3个字节,英文是1个字节
        fs.read(fd, buffer, 0, 9, 3, function (err, bytesRead, buffer) {
            if (err) {
                throw err;
            } else {
                console.log(bytesRead);
                console.log(buffer.slice(0, bytesRead).toString());
                //读取完后,再使用fd读取时,基点是基于上次读取位置计算;
                fs.read(fd, buffer, 0, 9, null, function (err, bytesRead, buffer) {
                    console.log(bytesRead);
                    console.log(buffer.slice(0, bytesRead).toString());
                });
            }
        });
    }
});

6.fs.write() 将缓冲区内数据写入使用 fs.open 打开的文件

用法:

// 使用缓冲区
fs.write(fd, buffer, offset, length, position, callback);
// 使用字符串
fs.write(fd, string, position, encoding, callback);

参数:此方法接受上述和以下所述的六个参数:

  • fd:使用 fs.open 打开成功后返回的文件描述符。
  • buffer:一个 Buffer 对象,v8 引擎分配的一段内存。
  • offset:整数,从缓存区中读取时的初始位置,以字节为单位。
  • length:整数,从缓存区中读取数据的字节数。
  • position:整数,写入文件初始位置;文件大小以字节为单位。
  • string:将字符串写入 fd 指定的文件。
  • encoding:默认编码值为 UTF-8。
  • callback(err, bytesRead, buffer):写入操作执行完成后回调函数,written实际写入字节数,buffer被读取的缓存区对象

返回值:回调函数接收到错误或写入的字节数。如果收到错误,则打印错误消息,否则打印写入的字节数。

完整示例:

fs.open(__dirname + "/test.txt", "a", function (err, fd) {
    if (err) {
        console.error(err);
        return;
    } else {
        var buffer = new Buffer("写入文件数据内容");
        //写入'入文件'三个字
        fs.write(fd, buffer, 3, 9, 12, function (err, written, buffer) {
            if (err) {
                console.log("写入文件失败");
                console.error(err);
                return;
            } else {
                console.log(buffer.toString());
                //写入'数据内'三个字
                fs.write(fd, buffer, 12, 9, null, function (err, written, buffer) {
                    console.log(buffer.toString());
                });
            }
        });
    }
});

7.fs.fsync() 刷新缓存区

fs.fsync()方法是一种异步形式。将文件与计算机上存储的文件同步。

用法:

fs.fsync(fd, callback);

参数:该方法接受上述和以下所述的两个参数:

  • fd:它是一种以同步方式获取的文件描述符(整数)。
  • callback(err, written, buffer):写入操作执行完成后回调函数,written实际写入字节数,buffer被读取的缓存区对象

返回值:此函数不返回任何值。

完整示例:

// 使用fs.write写入文件时,操作系统是将数据读到内存,再把数据写入到文件中,当数据读完时并不代表数据已经写完,因为有一部分还可能在内在缓冲区内。
// 因此可以使用fs.fsync方法将内存中数据写入文件;--刷新内存缓冲区;

fs.open(__dirname + "/test.txt", "a", function (err, fd) {
    if (err) throw err;
    var buffer = new Buffer("写一段nodejs编程");
    fs.write(fd, buffer, 0, 9, 0, function (err, written, buffer) {
        console.log(written.toString());
        fs.write(fd, buffer, 9, buffer.length - 9, null, function (err, written) {
            console.log(written.toString());
            fs.fsync(fd);
            fs.close(fd);
        });
    });
});

8.文件流读写文件

/*
 * 流,在应用程序中表示一组有序的、有起点有终点的字节数据的传输手段;
 * Node.js中实现了stream.Readable/stream.Writeable接口的对象进行流数据读写;以上接口都继承自EventEmitter类,因此在读/写流不同状态时,触发不同事件;
 * 关于流读取:Node.js不断将文件一小块内容读入缓冲区,再从缓冲区中读取内容;
 * 关于流写入:Node.js不断将流数据写入内在缓冲区,待缓冲区满后再将缓冲区写入到文件中;重复上面操作直到要写入内容写写完;
 * readFile、read、writeFile、write都是将整个文件放入内存而再操作,而则是文件一部分数据一部分数据操作;
 *
 * -----------------------流读取-------------------------------------
 * 读取数据对象:
 * fs.ReadStream 读取文件
 * http.IncomingMessage 客户端请求或服务器端响应
 * net.Socket    Socket端口对象
 * child.stdout  子进程标准输出
 * child.stdin   子进程标准入
 * process.stdin 用于创建进程标准输入流
 * Gzip、Deflate、DeflateRaw   数据压缩
 *
 * 触发事件:
 * readable  数据可读时
 * data      数据读取后
 * end       数据读取完成时
 * error     数据读取错误时
 * close     关闭流对象时
 *
 * 读取数据的对象操作方法:
 * read      读取数据方法
 * setEncoding   设置读取数据的编
 * pause     通知对象众目停止触发data事件
 * resume    通知对象恢复触发data事件
 * pipe      设置数据通道,将读入流数据接入写入流;
 * unpipe    取消通道
 * unshift   当流数据绑定一个解析器时,此方法取消解析器
 *
 * ------------------------流写入-------------------------------------
 * 写数据对象:
 * fs.WriteStream           写入文件对象
 * http.clientRequest       写入HTTP客户端请求数据
 * http.ServerResponse      写入HTTP服务器端响应数据
 * net.Socket               读写TCP流或UNIX流,需要connection事件传递给用户
 * child.stdout             子进程标准输出
 * child.stdin              子进程标准入
 * Gzip、Deflate、DeflateRaw  数据压缩
 *
 * 写入数据触发事件:
 * drain            当write方法返回false时,表示缓存区中已经输出到目标对象中,可以继续写入数据到缓存区
 * finish           当end方法调用,全部数据写入完成
 * pipe             当用于读取数据的对象的pipe方法被调用时
 * unpipe           当unpipe方法被调用
 * error            当发生错误
 *
 * 写入数据方法:
 * write            用于写入数据
 * end              结束写入,之后再写入会报错;
 */

1.创建读取流

用法:

fs.createReadStream(path, [options]);

参数:该方法接受上述和以下所述的两个参数:

  • path:文件路径。
  • options
    • flags:指定文件操作,默认’r’,读操作;
    • encoding:指定读取流编码;
    • autoClose:是否读取完成后自动关闭,默认 true;
    • start:指定文件开始读取位置;
    • end:指定文件开始读结束位置。

完整示例:

var rs = fs.createReadStream(__dirname + "/test.txt", { start: 0, end: 2 });
//open是ReadStream对象中表示文件打开时事件,
rs.on("open", function (fd) {
    console.log("开始读取文件");
});

rs.on("data", function (data) {
    console.log(data.toString());
});

rs.on("end", function () {
    console.log("读取文件结束");
});
rs.on("close", function () {
    console.log("文件关闭");
});

rs.on("error", function (err) {
    console.error(err);
});

//暂停和回复文件读取;
rs.on("open", function () {
    console.log("开始读取文件");
});

rs.pause();

rs.on("data", function (data) {
    console.log(data.toString());
});

setTimeout(function () {
    rs.resume();
}, 2000);

2.创建写入流

用法:

fs.createWriteStream(path, [options]);

参数:该方法接受上述和以下所述的两个参数:

  • path:文件路径。
  • options
    • flags:指定文件操作,默认’w’,读操作;
    • encoding:指定读取流编码;
    • start:指定写入文件的位置;

完整示例:

/* ws.write(chunk, [encoding], [callback]);
 * chunk,  可以为Buffer对象或一个字符串,要写入的数据
 * [encoding],  编码
 * [callback],  写入后回调
 */
/* ws.end([chunk], [encoding], [callback]);
 * [chunk],  要写入的数据
 * [encoding],  编码
 * [callback],  写入后回调
 */
var ws = fs.createWriteStream(__dirname + "/test.txt", { start: 0 });
var buffer = new Buffer("我也喜欢你");
ws.write(buffer, "utf8", function (err, buffer) {
    console.log(arguments);
    console.log("写入完成,回调函数没有参数");
});
//最后再写入的内容
ws.end("再见");
//使用流完成复制文件操作
var rs = fs.createReadStream(__dirname + "/test.txt");
var ws = fs.createWriteStream(__dirname + "/test/test.txt");

rs.on("data", function (data) {
    ws.write(data);
});

ws.on("open", function (fd) {
    console.log("要写入的数据文件已经打开,文件描述符是: " + fd);
});

rs.on("end", function () {
    console.log("文件读取完成");
    ws.end("完成", function () {
        console.log("文件全部写入完成");
    });
});

//关于WriteStream对象的write方法返回一个布尔类型,当缓存区中数据全部写满时,返回false;
//表示缓存区写满,并将立即输出到目标对象中

//第一个例子
var ws = fs.createWriteStream(__dirname + "/test/test.txt");
for (var i = 0; i < 10000; i++) {
    var w_flag = ws.write(i.toString());
    //当缓存区写满时,输出false
    console.log(w_flag);
}

//第二个例子
var ws = fs.createWriteStream(__dirname + "/test/untiyou.mp3");
var rs = fs.createReadStream(__dirname + "/test/Until You.mp3");
rs.on("data", function (data) {
    var flag = ws.write(data);
    console.log(flag);
});

//系统缓存区数据已经全部输出触发drain事件
ws.on("drain", function () {
    console.log("系统缓存区数据已经全部输出。");
});

3.管道 pipe 实现流读写

用法:

rs.pipe(destination, [options]);

参数:该方法接受上述和以下所述的两个参数:

  • destination:必须一个可写入流数据对象。
  • opations
    • end:默认为 true,表示读取完成立即关闭文件;

完整示例:

var rs = fs.createReadStream(__dirname + "/test/Until You.mp3");
var ws = fs.createWriteStream(__dirname + "/test/untiyou.mp3");
rs.pipe(ws);
rs.on("data", function (data) {
    console.log("数据可读");
});
rs.on("end", function () {
    console.log("文件读取完成");
    //ws.end('再见')
});

const writerStream = fs.createWriteStream(filePath);
await fs.createReadStream(wavPath).pipe(writerStream);
writerStream.on("finish", async () => {
    console.log("写入已完成..");
});

9.fs.stat 查看文件与目录的信息

fs.stat()方法用于返回有关给定文件或目录的信息。它返回一个fs.Stat对象,该对象具有几个属性和方法来获取有关文件或目录的详细信息。

在调用 fs.open()fs.readFile()fs.writeFile() 之前,不建议使用 fs.stat() 检查文件是否存在。 而是,用户代码应该直接打开/读取/写入文件,并在文件不可用时处理引发的错误。

要检查文件是否存在而不对其进行操作,建议使用 fs.access()

用法:

fs.stat(path, options, callback);

参数:该方法接受上述和以下所述的三个参数:

  • path:它包含必须检查的文件或目录的路径。它可以是字符串,缓冲区或 URL。
  • options:该对象可用于指定将影响输出的可选参数。它具有一个可选参数:
    • bigint:它是一个布尔值,它指定 fs.Stats 对象中返回的数值是否为 bigint。默认值为 false。
  • callback:执行该方法时将调用该函数。
    • err:如果该方法会引发错误
    • stats:Stats 对象包含文件路径的详细信息,如:isFile, isDirectory,isBlockDevice 等方法及 size,ctime,mtime 等属性。

完整示例:

fs.stat("example_file.txt", (error, stats) => {
    if (error) {
        console.log(error);
    }
    else {
        console.log("Stats object for:example_file.txt");
        console.log(stats);

        // Using methods of the Stats object
        console.log("Path is file:", stats.isFile());
        console.log("Path is directory:", stats.isDirectory());
    }
});

// 输出
Stats object for:example_file.txt
Stats {
  dev: 1588446912,
  mode: 33206,
  nlink: 1,
  uid: 0,
  gid: 0,
  rdev: 0,
  blksize: 4096,
  ino: 1407374883938641,
  size: 2328,
  blocks: 16,
  atimeMs: 1709177444552.9143,
  mtimeMs: 1709177444552.9143,
  ctimeMs: 1709177444552.9143,
  birthtimeMs: 1709177444552.9143,
  atime: 2024-02-29T03:30:44.553Z,
  mtime: 2024-02-29T03:30:44.553Z,
  ctime: 2024-02-29T03:30:44.553Z,
  birthtime: 2024-02-29T03:30:44.553Z
}
Path is file:true
Path is directory:false

其中:

atime是指access time,即文件被读取或者执行的时间,修改文件是不会改变 access time 的。网上很多资料都声称 cat、more 等读取文件的命令会改变 atime,这其实与系统设置有关的,一般默认不会修改。

ctimechange time,文件状态改变时间,指文件的 i 结点被修改的时间

mtimemodify time,指文件内容被修改的时间。

birthtime,即文件创建时间,很多文件系统不支持。

在不同的操作系统和设置下,atime/ctime/mtime 的更新规则是不一样的,比如我们在 Linux Debian 下实测的例子:

Debian 不支持 Birth 文件创建时间

使用 touch 创建,并使用 stat 查看文件状态

root@VM-104-49-debian:/var/www# touch test.log
root@VM-104-49-debian:/var/www# stat test.log
  File: ‘test.log’
  Size: 0               Blocks: 0          IO Block: 4096   regular empty file
Device: fe01h/65025d    Inode: 405946      Links: 1
Access: (0644/-rw-r--r--)  Uid: (    0/    root)   Gid: (    0/    root)
Access: 2017-05-24 14:48:15.376000000 +0800
Modify: 2017-05-24 14:48:15.376000000 +0800
Change: 2017-05-24 14:48:15.376000000 +0800
 Birth: -

可以看到 Birth 是空的。因此在 Debin 等 Linux 下面通过 states.birthtime 来判断文件创建时间会有各样的 BUG,

比如通过 fs.utimes 修改 atimemtime 时,在 debian 下 birthtime 也会更改。并且有时 birthtime 会比 mtime 更新。

查看文件不会改变 Access time

出于性能考虑使用 cat 查看文件内容,不会修改 atime,在 Windows 下也是同时,不过可以通过系统配置启用 atime 访问时间的自动更新

root@VM-104-49-debian:/var/www# cat test.log
root@VM-104-49-debian:/var/www# stat test.log
  File: ‘test.log’
  Size: 0               Blocks: 0          IO Block: 4096   regular empty file
Device: fe01h/65025d    Inode: 405946      Links: 1
Access: (0644/-rw-r--r--)  Uid: (    0/    root)   Gid: (    0/    root)
Access: 2017-05-24 14:48:15.376000000 +0800
Modify: 2017-05-24 14:48:15.376000000 +0800
Change: 2017-05-24 14:48:15.376000000 +0800
 Birth: -

修改文件内容 Modify、Change 时间会一同修改

无论是使用重写还是添加,(mtime,ctime)会一同改变

root@VM-104-49-debian:/var/www# echo 'abc' > test.log
root@VM-104-49-debian:/var/www# stat test.log
  File: ‘test.log’
  Size: 4               Blocks: 8          IO Block: 4096   regular file
Device: fe01h/65025d    Inode: 405946      Links: 1
Access: (0644/-rw-r--r--)  Uid: (    0/    root)   Gid: (    0/    root)
Access: 2017-05-24 14:48:15.376000000 +0800
Modify: 2017-05-24 14:49:38.372000000 +0800
Change: 2017-05-24 14:49:38.372000000 +0800
 Birth: -
root@VM-104-49-debian:/var/www# echo 'abc' >> test.log
root@VM-104-49-debian:/var/www# stat test.log
  File: ‘test.log’
  Size: 8               Blocks: 8          IO Block: 4096   regular file
Device: fe01h/65025d    Inode: 405946      Links: 1
Access: (0644/-rw-r--r--)  Uid: (    0/    root)   Gid: (    0/    root)
Access: 2017-05-24 14:48:15.376000000 +0800
Modify: 2017-05-24 14:49:46.324000000 +0800
Change: 2017-05-24 14:49:46.324000000 +0800
 Birth: -

更改文件属性只会改变 Change 时间

通过 chown 更新文件所属用户,只有 ctime 发生改变。

root@VM-104-49-debian:/var/www# chown newghost test.log
root@VM-104-49-debian:/var/www# stat test.log
  File: ‘test.log’
  Size: 8               Blocks: 8          IO Block: 4096   regular file
Device: fe01h/65025d    Inode: 405946      Links: 1
Access: (0644/-rw-r--r--)  Uid: ( 1000/newghost)   Gid: (    0/    root)
Access: 2017-05-24 14:48:15.376000000 +0800
Modify: 2017-05-24 14:49:46.324000000 +0800
Change: 2017-05-24 14:51:14.792000000 +0800

因此可以看出 states 的 atime 是非常类似于创建时间的,而且一般也不会被更改。所以在服务器上可代替创建时间使用。

fs.lstat()方法与fs.stat()方法类似,不同之处在于它用于返回有关用于引用文件或目录的符号链接的信息。返回的 fs.Stat 对象具有多个字段和方法,以获取有关文件的更多详细信息。

10.fs.utimes() 修改文件访问时间与修改时间

fs.utimes()方法用于异步更改文件的修改和访问时间戳。可以使用数字,字符串或 Date 对象指定时间戳。如果时间戳不能转换为正确的数字,或者是 NaN,Infinity 或-Infinity,则将引发错误。

用法:

fs.utimes(path, atime, mtime, callback);

参数:该方法接受上述和以下所述的四个参数:

  • path:它包含必须检查的文件或目录的路径。它可以是字符串,缓冲区或 URL。
  • atime:是数字,字符串或 Date 对象,表示要设置的新访问时间戳。
  • mtime:是数字,字符串或 Date 对象,表示要设置的新修改时间戳。
  • callback:执行该方法时将调用该函数。
    • err:如果该方法会引发错误

完整示例:

console.log("Details before changing time:");

// Get the stats object of the file
prevStats = fs.statSync("example_file.txt");

// Access the modified and access time of the file
console.log("Modification Time:", prevStats.mtime);
console.log("Access Time:", prevStats.atime);

// Get the current time to change the timestamps
let newModifiedTime = new Date();
let newAccessTime = new Date();

// Use the utimes() function to assign
// the new timestamps
fs.utimes(
    "example_file.txt",
    newAccessTime,
    newModifiedTime,
    () => {
        // Get the stats object of the file
        console.log("\nDetails after changing time:");

        // Get the stats object of the file
        changedStats = fs.statSync("example_file.txt");

        // Access the changed modified and
        // access time of the file
        console.log("Changed Modification Time:",changedStats.mtime);

        console.log("Changed Access Time:",changedStats.atime);
    }
);
// 输出
Details before changing time:
Modification Time:2017-01-24T23:41:00.000Z
Access Time:2018-02-26T00:05:00.000Z

Details after changing time:
Changed Modification Time:2020-05-25T15:31:08.257Z
Changed Access Time:2020-05-25T15:31:08.257Z

11.fs.chmod() 修改文件或目录的操作权限

fs.chmod()方法用于更改给定路径的权限。可以使用字符串常量或与它们各自的文件模式相对应的八进制数字来指定这些权限。

注意:Windows 平台仅支持更改写权限。它还不支持区分用户权限,组权限或其他权限。

用法:

fs.chmod(path, mode, callback);

参数:该方法接受上述和以下所述的两个参数:

  • path:它是一个字符串,Buffer 或 URL,表示必须更改其权限的文 ​​ 件的路径。
  • mode:是字符串或八进制整数常量,表示要授予的权限。逻辑 OR 运算符可用于分隔多个权限,指定权限,如:0666 8 进制,权限:所有用户可读、写。
  • callback:执行该方法时将调用该函数。 - err:如果该方法会引发错误
File modes

The mode argument used in both the fs.chmod() and fs.chmodSync() methods is a numeric bitmask created using a logical OR of the following constants:

常量 八进制 描述
fs.constants.S_IRUSR 0o400 文件所有者的读权限
fs.constants.S_IWUSR 0o200 文件所有者的写权限
fs.constants.S_IXUSR 0o100 文件所有者的写权限
fs.constants.S_IRGRP 0o40 文件所属组的读权限
fs.constants.S_IWGRP 0o20 文件所属组的写权限
fs.constants.S_IXGRP 0o10 文件所属组的执行权限
fs.constants.S_IROTH 0o4 其他用户的读权限
fs.constants.S_IWOTH 0o2 其他用户的写权限
fs.constants.S_IXOTH 0o1 其他用户的执行权限

完整示例:

// Grant only read permission to user
console.log("Granting only read access to user");

fs.chmod("example.txt", 0o400, () => {
    console.log("\nReading the file contents");
    console.log(fs.readFileSync("example.txt", 'utf8'));

    console.log("\nTrying to write to file");
    try {
        fs.writeFileSync('example.txt', "This file has now been edited.");
    }
    catch (e) {
        console.log("Error Code:", e.code);
    }

    // Grant both read and write permission to user
    console.log("\nGranting read and write access to user");
    fs.chmod("example.txt", 0o600, () => {
        console.log("Trying to write to file");
        fs.writeFileSync('example.txt', "This file has now been edited.");

        console.log("\nReading the file contents");
        console.log(fs.readFileSync("example.txt", 'utf8'));
    });
});

// 输出
Granting only read access to user

Reading the file contents
This is an example text file.

Trying to write to file
Error Code:EACCES

Granting read and write access to user
Trying to write to file

Reading the file contents
This file has now been edited.

12.fs.exists() 检查给定的路径是否存在

fs.exists()方法通过检查文件系统来测试给定的路径是否存在。 然后使用 true 或 false 调用 callback 参数

该方法已弃用,改用 fs.stat()fs.access() 。但仍可正常使用

此回调的参数与其他 Node.js 回调不一致。 通常,Node.js 回调的第一个参数是 err 参数,后跟可选的其他参数。 fs.exists() 回调只有一个布尔参数。 这是推荐 fs.access() 而不是 fs.exists() 的原因之一。

用法:

fs.exists(path, callback);

在调用 fs.open()fs.readFile()fs.writeFile() 之前,不建议使用 fs.exists() 检查文件是否存在。 这样做会引入竞争条件,因为其他进程可能会在两次调用之间更改文件的状态。

而是,用户代码应该直接打开/读取/写入文件,并在文件不存在时处理引发的错误

写入(不推荐)

import { exists, open, close } from "node:fs";

exists("myfile", e => {
    if (e) {
        console.error("myfile already exists");
    } else {
        open("myfile", "wx", (err, fd) => {
            if (err) throw err;

            try {
                writeMyData(fd);
            } finally {
                close(fd, err => {
                    if (err) throw err;
                });
            }
        });
    }
});

写入(推荐)

import { open, close } from "node:fs";
open("myfile", "wx", (err, fd) => {
    if (err) {
        if (err.code === "EEXIST") {
            console.error("myfile already exists");
            return;
        }

        throw err;
    }

    try {
        writeMyData(fd);
    } finally {
        close(fd, err => {
            if (err) throw err;
        });
    }
});

读取(不推荐)

import { open, close, exists } from "node:fs";

exists("myfile", e => {
    if (e) {
        open("myfile", "r", (err, fd) => {
            if (err) throw err;

            try {
                readMyData(fd);
            } finally {
                close(fd, err => {
                    if (err) throw err;
                });
            }
        });
    } else {
        console.error("myfile does not exist");
    }
});

读取(推荐)

import { open, close } from "node:fs";

open("myfile", "r", (err, fd) => {
    if (err) {
        if (err.code === "ENOENT") {
            console.error("myfile does not exist");
            return;
        }

        throw err;
    }

    try {
        readMyData(fd);
    } finally {
        close(fd, err => {
            if (err) throw err;
        });
    }
});

上面的“不推荐”示例检查是否存在,然后使用该文件;“推荐”示例更好,因为它们直接使用文件并处理错误(如果有)。

一般来说,只有在文件不被直接使用时才检查文件是否存在,例如当它的存在是来自另一个进程的信号时。

13.fs.access() 测试用户对 path 指定的文件或目录的权限

用法:

fs.exists(path, mode, callback);

参数:该方法接受上述和以下所述的三个参数:

  • path:文件路径。
  • mode:它是一个整数值,表示要测试的许可。逻辑OR运算符可用于分隔多个权限。它可以具有值
    fs.constants.F_OKfs.constants.R_OKfs.constants.W_OKfs.constants.X_OK。它是一个可选参数。默认值为fs.constants.F_OK
  • callback:该方法执行时将调用该函数。
    • err:如果方法失败,将抛出此错误。

在调用 fs.open()fs.readFile()fs.writeFile() 之前,不要使用 fs.access() 检查文件的可访问性。 这样做会引入竞争条件,因为其他进程可能会在两次调用之间更改文件的状态。 而是,用户代码应直接打开/读取/写入文件,并处理无法访问文件时引发的错误。

import { access, constants } from 'node:fs';

const file = 'package.json';

// 检查当前目录中是否存在该文件。
access(file, constants.F_OK, (err) => {
  console.log(`${file} ${err ? 'does not exist' : 'exists'}`);
});

// 检查文件是否可读。
access(file, constants.R_OK, (err) => {
  console.log(`${file} ${err ? 'is not readable' : 'is readable'}`);
});

// 检查文件是否可写。
access(file, constants.W_OK, (err) => {
  console.log(`${file} ${err ? 'is not writable' : 'is writable'}`);
});

// 检查文件是否可读可写。
access(file, constants.R_OK | constants.W_OK, (err) => {
  console.log(`${file} ${err ? 'is not' : 'is'} readable and writable`);
});

参考


文章作者: 弈心
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 弈心 !
评论
  目录