node.js 学习笔记2 进程/线程、fs

发布于:2025-08-09 ⋅ 阅读:(11) ⋅ 点赞:(0)

进程和线程

进程:进行中的程序。比如有一段程序,程序已经载入内存了,CPU正在执行这段程序,这时候就会产生一个进程。进程,也可以看做程序的一次执行过程。

在window中打开任务管理器,可以查看计算机中的所有进程。

线程:一个进程中执行的一个执行流。线程是属于某个进程的。一个进程中至少包含一个线程,可以有多个线程。比如进程A可能有一个线程a,进程B可能有线程a,b,c。

线程也可以通过指令查看。

pslist -dmx 进程ID。

进程ID可以在任务管理器中查看。

要使用pslist命令,需要先下载工具PSTools:PsTools - Sysinternals | Microsoft Learn

把下载的pstools.exe放在需要指令命令的目录下运行,然后打开cmd,就能使用命令了。

列出来的内容,就是当前进程使用的线程。

举例来说,比如有一个场景,是需要制作奶茶,制作奶茶这件事就可以看做进程,在这个进程中,有的人负责洗水果,有的人负责制作,这些都可以看做线程。

fs Api

fs是file system的缩写,是文件系统,fs模块可以实现与硬盘的交互,可以实现文件的创建、删除、重命名、移动,文件内容的读写、文件夹的相关操作等。

使用fs写入文件内容:

实现的效果:要创建一个文件,并往文件中写入一定内容

思路

导入fs模块:通过const fs = require('fs'),require是全局函数,可以用来导入模块。

写入文件:fs.writerFile(),writerFile(要写入的文件名,往文件里写入的数据,配置对象(如果没有可以不写),回调函数(在写入完成后调用,如果有错误,错误会以参数的形式传递给函数,错误以Error对象的格式返回。如果写入成功,参数值为null。))

如果写入的文件不存在,会自动创建新文件并写入。回调函数在fs代码调用完成后被执行,如果执行过程中产生了错误,错误信息会作为参数被传给回调函数。

配置对象:配置{flag:'a'},可以设置当前的写入是追加写入而不是覆盖。

通过fs Api,可以实现自动化,不需要人工创建文件并记录。

代码

const fs = require('fs');

fs.writeFile( './demo.txt','hello world',{},()=>{} );

运行后,会生成或修改目录下的demo.txt

const fs = require('fs');

fs.writeFile('./test.txt','afeaefafe',(err)=>{
    if(err){
        console.log('error!');
        return ;
    }
    console.log('ok');
})

fs 工作模式:异步与同步

同步模式:fs.writeFileSync()

writeFileSync的参数和writeFile类似,只不过没有回调函数。

当JS代码执行到writeFileSync时,会进入I/O线程进行处理,此时JS主线程就停止了不再执行。等I/O线程执行完毕,主线程才会继续执行。

fs.writeFileSync('./test.txt','afeaefafe');

异步模式:writeFile就是异步模式,当程序执行到writeFile,会把writeFile交给另一个线程去执行(这种用于输入输出的线程被称为I/O线程)。主线程继续执行JS代码。当I/O线程执行完毕后,会把回调函数压入任务队列。等JS主线程的基础代码执行完毕后,会进入任务队列处理队列中的程序。

由于writeFile是异步I/O,代码会先输出hello world,后打印ok。

fs 追加写入

fs.appendFile() 异步写入

参数为(文件路径,要追加的内容,配置对象,回调函数)

回调函数也有一个形参,形参跟writeFile一样,如果写入失败,返回Error对象,如果成功是null。

fs.appendFileSync(文件路径,要追加的内容,配置对象) 同步写入

在写要追加的内容时,使用\r\n表示换行。

追加写入一般用于记录相关信息,或者写日志。

fs 流式写入

创建写入流对象ws = fs.createWriteStream(写入流文件路径),相当于和写入流文件创建一个通道,当需要写入时,往通道里进行操作。

写入内容:ws.write(写入内容)

关闭通道:ws.close() 可选,如果不写,当脚本执行完毕,通道会被自动关闭

与writeFile相比,流式写入更适合写入频率更高的情况下。因为流式写入在关闭通道前,通道是一直链接着的。而writeFile在写入完毕后会断开链接,每次写入时会重复建立链接,断开链接。

文件写入的应用场景

下载文件、安装软件、保存程序日志、编辑器保存文件、视频录制等。

当需要持久化保存数据时,可以考虑文件写入。

fs文件读取

fs.readFile() 异步读取

参数为(文件路径,配置对象,回调函数)

回调函数有两个形参,第一个形参接收错误信息(失败为Error对象,成功为null),第二个参数接收读取到的信息(一个buffer)。

fs.readFileSync() 同步读取

参数没有回调函数。读取的内容是返回值。

文件读取可以用于自动化。

读取文件的应用场景

电脑开机、程序运行、编辑器打开文件、查看图片、播放视频、播放音乐、查看日志、上传文件、查看聊天记录等。

fs 流式读取

fs.createReadStream

流式读取的思想:就是读取文件时,一块一块读取,readFile读取文件时,是把文件内容整个一次性读取。

rs = fs.createReadStream(读取文件的路径) 创建读取流对象

绑定事件:rs.on(事件名,回调函数)

事件名为'data',表示读取数据:

回调函数有一个形参,推荐名是chunk,当从文件读取一块数据时,就执行一次回调函数,并把读取到的内容传给chunk。

流式读取时,每次默认读取65536字节,对应64KB。

对于chunk数据,单次chunk数据可能并不具有什么意义,使用.toString可能会获取乱码。

rs.on('end')  事件名为end,在读取流读取完毕后触发。

流式读取在读取大文件时,可以提高读取效率。

const fs = require('fs');

let rs = fs.createReadStream('./a.txt')

rs.on('data',(chunk)=>{
    console.log(chunk)
})

rs.on('end',()=>{
    console.log('finished');
})

fs应用例子:

使用fs复制文件:逻辑就是把文件中的内容读取,并复制到另一个文件。

const fs = require('fs');

//普通文件读取写入
const fileData = fs.readFileSync('./book.pdf');
fs.writeFileSync('./book-copy.pdf',fileData);

//流式文件读取写入
const rs = fs.createReadStream('./book.pdf');
const ws = fs.createWriteStream('./book-copy2.pdf');

rs.on('data',(chunk)=>{
    ws.write(chunk);
})

与一般的文件读写相比,流式文件读写更好,占的资源更少。当使用一般文件读写时,需要把文件整个读到内存,再整个写入硬盘,也就是说,读写的文件本身有多大,内存中就要留出多大的空间。

但使用流式文件读写时,由于数据一块一块读写的,理想状态下只需要占用64kb的内存空间(但是读的速度一般比写入的速度快,所以实际上内存空间占用是比64kb多的,但其占用空间还是比整个文件读取要小)。

当使用流式文件读取时,可以使用rs.pipe(ws)实现文件读取。

//流式文件读取写入
const rs = fs.createReadStream('./book.pdf');
const ws = fs.createWriteStream('./book-copy2.pdf');

rs.pipe(ws)

fs文件重命名

fs.rename() 异步

参数是(文件旧路径,文件新路径,回调函数)

回调函数的形参是error,和读写文件的形参一致。

fs文件移动

fs.rename(旧路径,新路径,回调函数)

把新路径写在不同的文件路径下,就能实现文件移动。

fs.renameSync 同步,参数里没有回调函数

fs文件删除

fs.unlink()

参数是(删除的文件路径,回调函数)

回调函数的形参是error,和之前的方法一致。

node.js14.4及之后提供fs.rm方法,也可以删除文件。且参数是一致的。

对应的同步方法是fs.unlinkSync和fs.rmSync。

fs文件夹操作

创建文件夹

fs.mkdir()

参数是(文件夹路径,配置对象,回调函数)

配置{recursive:true},可以递归创建文件(当某个文件需要在前一个文件创建好之后,进入前一个文件路径下继续创建文件的情况)。

const fs = require('fs');

fs.mkdir('/a1/a2/a3',{recursive:true},(err)=>{
    if(err){
        console.log('fail');
        return;
    }
    console.log('ok');
})

有同步方法fs.mkdirSync。

读取文件夹

fs.readdir()

参数是(读取路径,回调函数)

回调函数的参数是(错误信息,读取到的文件夹内容)

返回的读取到的内容是一个数组,数组里是每个文件的名称。

有同步方法fs.readdirSync。

删除文件夹

fs.rmdir()

参数是(删除文件夹的路径,配置对象,回调函数) 回调函数的形参是(错误信息)

删除也可以递归删除,除了删除某个文件夹,还希望删除文件夹内部的内容,需要配置{recursive:true}。有同步方法fs.rmdirSync。

fm.rm() 

语法和rmdir一致。有同步方法fs.rmSync。

fs查询资源信息

fs.stat()

stat是status的简写

参数是(资源路径,回调函数)

回调函数的参数是(错误信息,资源信息对象)

可以对资源信息对象应用一些方法,判断文件是否是某种类型:isFile 判断资源是不是文件,isDirectory 判断资源是不是文件夹。

fs路径

路径分为相对路径 和 绝对路径。

相对路径:路径相对于当前目录,./index   index表示当前文件夹下,../表示上一级路径。

绝对路径:以盘符开头的路径,是完整的路径。或者以/开头路径,表示当前盘符下的根目录路径。

相对路径的注意点:在JS中,相对路径参照的并不是当前js文件所在的路径,而是命令行的工作目录。也就是说,如果在某个js中,写了./demo.text,希望这个txt生成在和js同一路径的目录下,如果命令行工作目录和js文件夹在同一目录下才能实现这种效果,如果命令行工作目录在其他目录,这个文件实际上会被生成在命令行工作目录。

const fs = require('fs');

fs.writeFileSync('./demo.txt','afeaefae');

在d:\nodeDemo下创建demo.js文件,但在d:\下运行demo.js文件,由于命令行工作路径是d:\,最终demo.txt会被创建在d:\下。

所以,相对路径其实并不固定,他会随着工作路径的改变而改变。

可以通过__dirname来解决这个问题:

解决的思路就是把相对路径改成绝对路径,但是每次都敲绝对路径也很冗余,nodeJS中提供了__dirname可以优雅地解决这个问题。

__dirname保存的是所在文件的所在目录的绝对路径。也就是说,这个路径是js文件所在的绝对路径。

const fs = require('fs');

fs.writeFileSync(__dirname + '/demo.txt','afeaefae');


网站公告

今日签到

点亮在社区的每一天
去签到