進程和線程
進程:進行中的程序。比如有一段程序,程序已經載入內存了,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');