Node之文件IO
因为 Node 运行在操作系统上,可以通过 Node 操作系统上面的文件。比如对文件的读取和写入。也就是对外部设备的输入和输出。实际上,只有 cpu 和内存属于内部设备,其他像磁盘,显卡,网卡等等都属于外部设备。而且 IO ,也就是输入输出的速度远小于内存和 CPU 的交互速度。
const path = require('path');
const fs = require('fs');
const filename = path.resolve(__dirname, './myfiles/1.txt');
// fs.readFile(filename, {
// encoding: 'utf-8'
// },
// (err, data) => {
// console.log(data);
// })
// const content = fs.readFileSync(filename, 'utf-8');
// console.log(content);
// console.log('after readFileSync');
async function read() {
const content = await fs.promises.readFile(filename, 'utf-8');
console.log(content);
}
read();
console.log('after read');
当我们在读取文件的时候,可以使用 fs.readFile() 来读取,第一个参数是文件路径,第二个参数是一个回调函数。回调函数第一个参数为错误,第二个参数为回调返回的结果。
文件路径使用绝对路径,用 path.resolve() 来传入路径。如果传入相对路径,它会基于命令行的路径来执行。通过 __dirname 当前模块文件目录和后面的文件路径拼接起来可以得到路径。
可以在中间传入一个配置对象或者编码,来指定转换后的编码格式。
可以加一个 Sync 来实现同步的操作,一般不要使用,除了在刚启动时必须运行的一些文件。而且只能运行有限的次数。否则由于js是单线程的,会非常影响性能,导致阻塞。
此外,还可以使用 promise 的模式进行操作。
async function write() {
// await fs.promises.writeFile(filename, '怎么了,朋友' + os.EOL,{
// flag: 'a'
// });
// console.log('content written');
const buffer = Buffer.from('这是一个buffer' + os.EOL, 'utf-8');
await fs.promises.writeFile(filename, buffer, {
flag: 'a'
});
}
write();
文件写入使用 writeFile() ,第二个参数传入写入的内容,第三个参数默认为 'utf-8' ,可以传入标识符 a 来表示追加内容,而不是默认的覆盖内容。
文件写入不返回内容。buffer 是一个字节为单位,也就是两个16进制的数字组成。
async function copy(){
// await fs.promises.copyFile(
// path.resolve(__dirname,'./myfiles/1.txt'),
// path.resolve(__dirname,'./myfiles/2.txt')
// )
const fromFilename=path.resolve(__dirname,'./myfiles/1.txt');
const content=await fs.promises.readFile(fromFilename,"utf-8");
const toFilename=path.resolve(__dirname,'./myfiles/2.txt');
await fs.promises.writeFile(toFilename,content,{
flag:'a'
});
console.log('复制成功');
}
copy();
还可以手动复制文件过去。fs 也提供了复制的 API。
async function state() {
const filename = path.resolve(__dirname, './myfiles')
const stat = await fs.promises.stat(filename)
console.log(stat);
console.log(stat.isFile());
console.log(stat.isDirectory());
}
state();
还可以获取文件或者目录的信息。其中包括 size ,占用的字节空间,atime,上次访问时间,mtime,上次内容修改时间,ctime,上次状态修改时间,birthtime,文件创建时间,isDirectory(),是否是目录,isFile() 是否是文件。
注意,文件夹的大小为0,因为文件夹也是一个文件,只是里面存放了指向内部文件的指针,所以字节为0。
async function read() {
const filename = path.resolve(__dirname, './myfiles')
const pathes = await fs.promises.readdir(filename)
console.log(pathes);
}
read();
读取一个目录下的子文件,包括文件夹,因为文件夹也是一个特殊的文件。不能读取子文件再往下的文件。得到的是数组形式,数组中包含了每个文件的字符串名称。
async function mkdir() {
const filename = path.resolve(__dirname, './myfiles/a')
await fs.promises.mkdir(filename)
}
mkdir();
可以创建一个目录,创建一个文件可以使用 writeFile 创建一个空文件。
const dirname = path.resolve(__dirname, "./myfiles/b");
async function exists(filename) {
try {
await fs.promises.stat(filename);
return true;
}
catch (err) {
if (err.code === "ENOENT") {
//文件不存在
return false;
}
console.dir(err);
}
}
async function test() {
const result = await exists(dirname);
if(result){
console.log("目录已存在,无需操作");
}else{
await fs.promises.mkdir(dirname);
console.log("目录创建成功");
}
}
test();
手动判断文件是否存在,利用 exists 方法进行判断。因为官方已经禁止了 exists 的 promise 方法。如果已经存在就不用操作,否则需要创建相关的目录。
class File {
constructor(filename, name, ext, isFile, size, createTime, updateTime) {
this.filename = filename;
this.name = name;
this.ext = ext;
this.isFile = isFile;
this.size = size;
this.createTime = createTime;
this.updateTime = updateTime;
}
async getContent(isBuffer = false) {
if (this.isFile) {
if (isBuffer) {
return await fs.promises.readFile(filename);
} else {
return await fs.promises.readFile(filename, "utf-8");
}
}
return null;
}
async getChildren() {
if (this.isFile) {
return [];
}
let children = await fs.promises.readdir(this.filename);
children = children.map((name) => {
const result = path.resolve(this.filename, name);
return File.getFile(result);
})
return Promise.all(children);
}
static async getFile(filename) {
const stat = await fs.promises.stat(filename);
const name = path.basename(filename);
const ext = path.extname(filename);
const isFile = stat.isFile();
const size = stat.size;
const createTime = new Date(stat.birthtime);
const updateTime = new Date(stat.mtime);
return new File(filename, name, ext, isFile, size, createTime, updateTime);
}
}
async function readDir(dirname) {
const file = await File.getFile(dirname);
return await file.getChildren();
}
async function test() {
const filename = path.resolve(__dirname, './myfiles/');
const result = await readDir(filename);
const datas = await result[2].getChildren();
console.log(datas);
}
test()
想要实现通过一个目录就得到一个对象结构,里面包含了各种信息。并且可以通过子文件继续查找。里面有各种属性和查找文件和文件夹的方法。
这种类型可以通过类的方式实现,通过里面的各种属性来实现,以及添加一个静态属性来方便在查找子文件的时候进行调用。查找内容,如果是文件夹,返回 null 。查找文件夹,如果是文件,返回 [],否则通过 map 方法可以返回每一个子文件的属性。