初識Linux(14)Ext系列?件系統

之前談論的都是已打開文件在操作系統的中的管理,但是還有更多的文件沒有被打開,被存在磁盤中,如何管理這些磁盤中的文件,就是本篇的學習目標。

目錄

1.理解硬件

磁盤結構

扇區的讀寫

CHS地址定位

磁盤的邏輯結構

2. 引??件系統

分區

inode :? ?

Data Blocks:

Bitmap:

Super Block和GDT

格式化

inode與block的分配

3. inode和block的映射

4. 目錄文件(重點)

5. dentry(directory entry)

6. 文件描述符、內存、進程與 目錄緩存路徑 的關系?(難點)

7. 掛載mount(了解)


1.理解硬件

磁盤、服務器、機柜、機房

計算機中有許多重要的硬件,比如寄存器(由各種各樣的門電路邏輯電路組合而成),而機械磁盤是計算機中的唯一的一個機械設備。

磁盤是一種外設,不同于現在的ssd卡,雖然早期的磁盤都相對速度慢,同時單位容量的價格也更便宜,任然廣泛運用于計算機中。

磁盤、二進制

計算機只認識二進制?是一種宏觀表示,這個二進制的具體實現在不同的物理設備上有不同的具體體現。

比如高低電平,網卡上的電脈沖,或者是磁盤上的NS磁性

所以,在磁盤中,改變0、1,其實是將N極改成S極,或者將s極改成n極,然后由磁性得到1或者0

? ? ? ? ? ? ? ? ? ? ?

磁頭和磁盤是懸浮著(距離極小)的,外殼相對于內層一定是完全密封的,因為灰塵直徑遠大于磁頭和磁盤的距離,灰塵在上方撞擊可能導致數據丟失的問題。主軸能讓磁盤旋轉,永磁鐵能讓磁頭沿半徑移動,讀取所有 磁道 上的內容

真實情況:

相鄰磁極之間的磁性遠大于內部的磁性,所以本質是用兩個微磁體之間是否由磁性來確定1和0。

磁盤結構

側面來看 ,磁盤可以分成三層或者兩層或者四層等(下圖是三層),每層兩個面都能記錄數據;

俯視來看,每個面上,不同的半徑形成的是不同的磁道,一定距離的磁道構成一個扇區

? ? ? ? ? ? ? ? ? ?

所有面上的相同半徑構成了一個圓柱面,

扇區:是磁盤存儲數據的基本單位,512字節,塊設備(就算只訪問這512字節當中的一個字節,也需要全部訪問這個扇區,整個扇區是一塊完整的存儲結構)
從最外圈的磁道開始,編號為0,然后依次向內遞增;盤面的編號也是從0開始的。
這一點在之后的計算中有用。

扇區的讀寫

? ? ? ? ? ??

能定位在任何磁道上,就能定位在任何扇區上。

如何定位?個扇區呢?
?
可以先確定磁頭要訪問哪?個柱?(磁道)(cylinder)
?
再定位磁頭(哪一層)(header)
?
定位?個扇區(sector)

CHS地址定位

?件 = 內容+屬性 都是數據,??就是占據那?個扇區的問題!
我們認為不同半徑的磁道所能容納的扇區的數量是一樣的,但是 靠近主軸的同?圓?于停靠磁 頭,不存儲數據
磁盤容量 = 柱面個數(磁道數)*磁頭數(層數)*每個磁道扇區數*每個扇區字節數

就像一個三維坐標,只要知道了磁道位置/磁頭位置以及第幾扇區,就能定位扇區。

對早期的磁盤?常有效,知道?哪個磁頭,讀取哪個柱?上的第?扇區就可以讀到數據了。
但是CHS模式?持的硬盤容量有限,不夠長。

磁盤的邏輯結構

將磁道上的扇區化曲為直,得到LBA的概念。

LBA(Logic Block Address)是一種邏輯抽象,但是實際去找的時候是否還是需要去轉換成CHS

LBA將扇區的變成一個一個獨立的單元,像三維數組一樣聯系到一起,

? ? ? ? ? ? ? ? ? ? ? ? ??

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

整個盤:

同時,可以用一維數組來構建具體的LBA地址:

? ?半徑為r的一個盤面上的一個磁道:? ? ? ? ? ? ? ? ? ? ? ?

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??

由該磁道相同半徑的磁道組成的柱面:

多個柱面組成整個邏輯結構:

一個三維數組就被我們抽象成一維的線性存儲模式!!

***重點!!!

對于OS來說,知道LBA地址即可,LBA地址與CHS地址的轉換由磁盤??來做!固件(硬件電路,伺服系統)

注意:柱面號、磁頭號通常都是從0開始編號的。這種編號方式是硬盤存儲結構的一種約定俗成的規定,有助于硬盤控制器和操作系統對磁盤進行統一的尋址和數據管理。所以,一個CHS地址的柱面號表示的是當前所用地址以外已經被完全占滿的柱面。?

每?個扇區都有?個下標,我們叫做LBA(Logical Block Address)地址,其實就是線性地址。所以 ,怎么計算得到這個LBA地址呢?
CHS轉成LBA:
?
磁頭數*每磁道扇區數 = 單個柱?的扇區總數
?
LBA = 柱?號C*單個柱?的扇區總數 + 磁頭號H*每磁道扇區數 + 扇區號S - 1
?
即:LBA = 柱?號C*(磁頭數*每磁道扇區數) + 磁頭號H*每磁道扇區數 + 扇區號S - 1
?
扇區號通常是從1開始的,?在LBA中,地址是從0開始的
?
柱?和磁道都是從0開始編號的
?
總柱?,磁道個數,扇區總數等信息,在磁盤內部會?動維護,上層開機的時候,會獲取到這些參
數。
LBA轉成CHS:
?
柱?號C = LBA // (磁頭數*每磁道扇區數)【就是單個柱?的扇區總數】
?
磁頭號H = (LBA % (磁頭數*每磁道扇區數)) // 每磁道扇區數
?
扇區號S = (LBA % 每磁道扇區數) + 1
?
"//": 表?除取整
以上公式都不需要死記硬背,對于工科生來說,理解這個圖就能理解換算辦法。

2. 引??件系統

操作系統讀取硬盤數據的時候,其實是不會?個個扇區地讀取,這樣
效率太低,?是?次性連續讀取多個扇區,即?次性讀取?個”塊”(block)。畢竟磁盤是外部設備,每次IO都有成本。
因此, 磁盤也是一種“塊”設備。
硬盤的每個分區是被劃分為?個個的”塊”。?個”塊”的??是由格式化的時候確定的,并且不可以更改,最常?的是4KB,即連續?個扇區組成?個 ”塊”。”塊”是?件存取的最?單位。

所以,8個LBA數據構成一個“塊”,即塊號 = LBA // 8,LBA=塊號*8+n(n是指該塊中的哪個扇區)

或者 塊號*8=該塊的LBA起始地址


分區

對于win系統來說,我們有C盤D盤E盤F盤等等,其實這就是一個硬盤中分區的表示。

每個分區獨立,可以裝不同的文件系統,分區之間互不影響。

分治思想:管好一個組,就能管好所有的組。我們先研究操作系統如何管理分區中的一個組:
比如,我們將 group0 分成很多個 block group
data block所占空間遠大于其他的幾個模塊
文件=內容+屬性,類似于PCB或者struct files,inode就是管理磁盤上文件屬性的結構體
Boot Sector也稱作啟動區,大小為1kb,任何文件系統都不能改變啟動區的內容!!
啟動區里存放了啟動信息和分區信息。
宏觀來說,inode存文件屬性,data block存文件內容
inode里面有相關的映射內容,便于去data block中找具體的文件內容。
在linux系統下,文件名不會存在inode中。
我們認為,inode是128字節大小,一個塊(win系統中叫簇)能存32個inode(4*1024 / 128)? ?? ? ? ? ? ? ? ? ? ??
每一個分組都有這些固定字段,我們依次介紹。

inode :? ?

?
存放?件屬性 如 ?件??,所有者,最近修改時間等
?
當前分組所有Inode屬性的集合
?
inode編號以分區為單位,整體劃分,不可跨分區
我們還認為:
inode結構里還有個block數組,這個數組用于記錄屬于該inode對應文件內容所存儲的塊號

Data Blocks:

按照“塊”的大小一個一個存儲在內存中,一個塊4字節,用于存儲文件內容。

Bitmap:

inode Bitmap:
來顯示inode是否存在的位圖。比如該區域有8個inode,位圖為0010 0001,則表示第1、6個已經有內容了。
一個塊寫進內存(一萬個比特位的位圖也才不到2kb,一個塊4kb),所以不影響我們前文提到的內存要加載4kb來進行操作。整體修改完了再寫出來即可。
Block Bitmap :同理,檢測對應的data blocks是否合法的存在(是否已經被使用)。

Super Block和GDT

SB一般在每個分組的第一個字段中,存儲的是該分區的文件系統信息(每個分區的文件系統可以不一樣),但并不是每個分組中都有,也不是只有第一個分組有,這樣能保證一個超級塊出問題時,其他超級塊能用正確的信息來修復。當所有的超級塊都被破壞時,說明這個文件系統已經崩潰了。該字段記錄的包括不限于:總的inode數和block數,還能使用的inode數和block數,最近一次掛載時間、修改時間等。

struct ext2_super_block {
__le32 s_inodes_count; /* Inodes count */
__le32 s_blocks_count; /* Blocks count */
__le32 s_r_blocks_count; /* Reserved blocks count */
__le32 s_free_blocks_count; /* Free blocks count */
__le32 s_free_inodes_count; /* Free inodes count */
__le32 s_first_data_block; /* First Data Block */
__le32 s_log_block_size; /* Block size */
__le32 s_log_frag_size; /* Fragment size */
__le32 s_blocks_per_group; /* # Blocks per group */
__le32 s_frags_per_group; /* # Fragments per group */
__le32 s_inodes_per_group; /* # Inodes per group */

GDT:塊組描述符,描述當前塊組中哪里到哪里是哪些內容。

創建一個文件可能(只寫了hello world)的完整步驟:
先在inode bitmap中找一個可以用的位置,將0置1,加載對應的文件屬性到 inode 中去,此時文件內容少,直接將內容放到inode指向的data block中去。
刪一個文件,相當于是把inode Bitmap和Block Bitmap對應的比特值從0置1
所以刪除一個文件是可以恢復的。
刪除的本質其實是讓文件無效,刪除之后,如果想恢復,最好的辦法就是什么都不做,避免被其他文件覆蓋,覆蓋了就真的無了

格式化

? ? ? 我們想要在硬盤上儲?件,必須先把硬盤格式化為某種格式的?件系統,才能存儲?件。?件系統的?的就是組織和管理硬盤中的?件。
格式化的本質是在一個分區中寫入新的(空的)文件系統,兩個bitmap要清0,GDT里的使用率要降到0,SB中未使用的block和inode要加到最大。
包括在win系統中,格式化也是對于每一個分區來說的!
從分區落實到分組,每個組里的inode和block的個數是動態計算后固定的,所以比例也是固定的。
inode和block會成比例分配!
比如一個inode分配十個block,這比例是固定的。
磁盤中存在inode被分配完的情況(都是小文件)。
一個組里面的inode的值是固定的,都是從a~b
一整個 分區(C盤,D盤) 的inode是一套?
一整個 分區 的block也是一套。

inode與block的分配

每個分組占據了多少編號到多少編號的inode或者block都記錄在GDT里
因此,每次只需要確定每個分組的起始inode值即可。block同理。
可以 跨組(Block group0,Block group1)?建立塊號和inode的映射關系,inode和block的映射關系是在全局建立的。
但是inode和block的編號都是分區獨立,分組分配的。
?
分區之后的格式化操作,就是對分區進?分組,在每個分組中寫?SB、GDT、Block
Bitmap、Inode Bitmap等管理信息,這些管理信息統稱: ?件系統
?
只要知道?件的inode號,就能在指定分區中確定是哪?個分組,進?在哪?個分組確定
是哪?個inode
?
拿到inode?件屬性和內容就全部都有了,可以通過Inode完成對文件的增刪查改
根據inode找文件內容的大概流程:
查區間,inode減去起始編號,查對應的bitmap,從而查到對應的inode table中的數據,根據映射關系找到data block

3. inode和block的映射

一個inode128字節,一個指針4字節,就算全部存指針,也只能存32個塊,一個塊能存4kb,32*4 = 128kb,甚至不到1MB,這樣的文件也太小了吧!!

一共有15個塊指針,12個是直接塊指針,還有三個間接塊指針。?

比如一級間接塊索引,,指向的是一個不裝文件數據、只存其他塊號的塊,一個塊能存1024個塊號,相當于通過這個一級索引能找1024*4kb=4mb的空間。同理,二級索引指向的全是
只存一級索引塊,能裝4gb,三級能裝4tb。
所以,一個inode實際能裝的大小遠超過一個正常文件的大小,甚至大于整個磁盤的大小。

4. 目錄文件(重點)

linux文件系統基礎--VFS中的file、dentry和inode--講得非常透的一篇文章_vfs dentry-CSDN博客

建議有能力的讀者去看看這篇深度好文。

/就是一個目錄文件,/user也是一個目錄文件,文件夾就是目錄,前者是win的概念,后者是linux的概念,目錄文件存放他下面的“子目錄文件的文件名和inode的映射”以及普通文件的文件名和inode的映射,每個文件的inode和文件名的映射是存在其所在的文件夾中的。

在上層使用時,好像從來沒有用過inode,都是直接操作文件名。文件名和inode的關系是什么??

正如上所述,在linux中,文件名不存儲在inode中,文件名的信息是存在其所存在的目錄

所以地址的意義就在此,/user/zhangsan/test.cc,在/中找user文件名(即“user”)對應的inode,找到這個inode在其對應的data block中找到zhangsan對應的inode,依次找到test.cc,將test.cc加載到內存中去.......

進程都有CWD的意義也在于此,通過CWD(再加上open等函數)就能拼成所需的完整路徑,讓操作系統永遠都能獲得一個完整路徑。
為什么以inode作為比較、查找的對象?因為整數的查找添加等比字符串簡單。
這樣更高效。類似于GID、UID和USERNAME這種關系,字符串是給用戶看的。

5. dentry(directory entry)

兩個現象:
1,在文件夾中能直接進行tree命令
2,諸如下圖這種情況,只能不斷的訪問磁盤文件系統嗎?
文件系統是外設,速度很慢!

解決辦法:引入結構體dentry。?

將曾經訪問過、經常訪問的路徑在內存中緩存起來,形成一棵多叉樹,這樣就不需要一直訪問磁盤了!!!

6. 文件描述符、內存、進程與 目錄緩存路徑 的關系?(難點)

task_struct中的files_struct維護該進程打開的文件列表,列表中存的是一個個打開的file對象(經過VFS系統封裝出來的,讓所有文件都是file對象), 通過file對象,我們可以找到包括但不止于:1文件對應的操作表(就是將每個文件的具體操作封裝成write,read等接口的函數指針數組),2文件內核緩沖區(緩沖夠了直接由OS往外設發送),3 ?f_path,f_path指向了一個包含dentry的結構體。再觀察dentry的結構,有parent和child,由此說明dentry維護的 的確是一個樹形結構。
dentry里還有一個inode對象,其對應的 inode值 就是此時file所對應的 inode值
file中前面兩個包含的結構是在上一篇文章中學習過的,提出來只是為了復習。

所以當一個目錄文件被打開后,不再需要去訪問磁盤找data block從而找到子目錄或文件,而是能通過file中的dentry直接找到子目錄或文件(dentry已經在內存中了!!!!)?

注意:不是將整個結構樹給塞進內存,而是將結構記錄在dentry中,加載對應的文件的時候就能把該文件所對應的目錄關系給加載到內存中去。?

最終,就能通過dentry找到希望打開文件的inode了。
? ? ? ? 這個樹形結構,整體構成了Linux的路徑緩存結構,打開訪問任何?件,都在先在這
棵樹下根據路徑進?查找,找到就返回屬性inode和內容,沒找到就從磁盤加載路徑,添加dentry 結構,緩存新路徑

7. 掛載mount(了解)

df -h 查看磁盤的掛載狀態。
linux中, 必須將分區掛載到一個文件目錄樹上才能使用該分區
Mounted on : 掛載
使用指令建立好分區之后進行查找:
剛創建好是查不到也用不了的,要先掛載才能用
掛載和查看操作:

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/73400.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/73400.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/73400.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

電機控制常見面試問題(十二)

文章目錄 一.電機鎖相環1.理解鎖相環2.電機控制中的鎖相環應用3.數字鎖相環(DPLL) vs 模擬鎖相環(APLL)4.鎖相環設計的關鍵技術挑戰5.總結 二、磁鏈觀測1.什么是磁鏈?2.為什么要觀測磁鏈?3.怎么觀測磁鏈&am…

Android `%d` 與 `1$%d` 格式化的區別

在 Android 開發中,我們經常需要對字符串進行格式化處理,比如動態填充數字、日期、字符等。 其中,%d 和 1$%d 都是格式化占位符,但它們在使用上有一些不同。 本文將詳細解析這兩者的區別,并結合 Kotlin 代碼示例幫助你…

SpringBoot中使用kaptcha生成驗證碼

簡介 kaptcha是谷歌開源的簡單實用的驗證碼生成工具。通過設置參數&#xff0c;可以自定義驗證碼大小、顏色、顯示的字符等等。 Maven引入依賴 <!-- https://mvnrepository.com/artifact/pro.fessional/kaptcha --><dependency><groupId>pro.fessional<…

如何在PHP中實現數據加密與解密:保護敏感信息

如何在PHP中實現數據加密與解密&#xff1a;保護敏感信息 在現代Web開發中&#xff0c;數據安全是一個至關重要的議題。無論是用戶的個人信息、支付數據&#xff0c;還是其他敏感信息&#xff0c;都需要在存儲和傳輸過程中進行加密&#xff0c;以防止數據泄露和惡意攻擊。PHP作…

單元測試、系統測試、集成測試、回歸測試的步驟、優點、缺點、注意點梳理說明

單元測試、系統測試、集成測試、回歸測試的梳理說明 單元測試 步驟&#xff1a; 編寫測試用例&#xff0c;覆蓋代碼的各個分支和邊界條件。使用測試框架&#xff08;如JUnit、NUnit&#xff09;執行測試。檢查測試結果&#xff0c;確保代碼按預期運行。修復發現的缺陷并重新測…

C++能力測試題

以下是一些C能力測試題&#xff0c;涵蓋了從基礎語法到高級特性的多個方面&#xff1a; 選擇題 1. 下面關于RTTI的說法&#xff0c;正確的是&#xff1f; A. 使用typeid前必須包含<type_info>頭文件。 B. typeid只能用于多態類型或表達式。 C. typeid可以用于不完整類型…

模擬類似 DeepSeek 的對話

以下是一個完整的 JavaScript 數據流式獲取實現方案&#xff0c;模擬類似 DeepSeek 的對話式逐段返回效果。包含前端實現、后端模擬和詳細注釋&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><titl…

【訓練細節解讀】文本智能混合分塊(Mixtures of Text Chunking,MoC)引領RAG進入多粒度感知智能分塊階段

RAG系統在處理復雜上下文時,傳統和語義分塊方法的局限性,文本分塊的質量限制了檢索到的內容,從而影響生成答案的準確性。盡管其他算法組件有所進步,但分塊策略中的增量缺陷仍可能在一定程度上降低整體系統性能。如何直接量化分塊質量?如何有效利用大型語言模型(LLMs)進行…

IMA+DeepSeekR1+本地知識庫撰寫NOIP2008普及組T3【傳球游戲】題解

目錄 一、提問詞 二、DeepSeekR1回復 題目描述 解題思路 實現代碼 代碼說明 三、說明 【IMADeepSeekR1本地知識庫】撰寫NOIP2008普及組復賽題解系列 1、IMADeepSeekR1本地知識庫撰寫NOIP2008普及組T1【ISBN 號碼】題解-CSDN博客 2、IMADeepSeekR1本地知識庫撰寫NOIP200…

Nginx正向代理HTTPS配置指南(僅供參考)

要使用Nginx作為正向代理訪問HTTPS網站&#xff0c;需通過CONNECT方法建立隧道。以下是操作詳細步驟&#xff1a; 1. 安裝Nginx及依賴模塊 需要模塊&#xff1a;ngx_http_proxy_connect_module&#xff08;支持CONNECT方法&#xff09;。 安裝方式&#xff1a;需重新編譯Nginx…

Python 實現機器學習的 房價預測回歸項目

項目目標&#xff1a; 基于房屋特征&#xff08;如房間數、地理位置等&#xff09;預測加州地區的房價中位數。 使用 Python 實現機器學習的 房價預測回歸項目&#xff08;使用 California Housing 數據集&#xff09; 環境準備 # 安裝必要庫&#xff08;若未安裝&#xff09…

聚力·突破·共贏|修飾組學服務聯盟正式成立,共啟協同發展新篇章

2025年3月13日&#xff0c;上海——由中科新生命、杭州微米生物、廣科安德、承啟生物、派森諾生物、胡珀生物等十余家行業標桿企業共同發起的“修飾組學服務聯盟”成立儀式在上海紫竹新興產業技術研究院隆重舉行。聯盟以“聚力突破共贏”為主題&#xff0c;致力于整合修飾組學全…

【Docker項目實戰】使用Docker部署serverMmon青蛇探針(詳細教程)

【Docker項目實戰】使用Docker部署serverMmon青蛇探針 一、serverMmon介紹1.1 serverMmon 簡介1.2 主要特點二、本次實踐規劃2.1 本地環境規劃2.2 本次實踐介紹三、本地環境檢查3.1 檢查Docker服務狀態3.2 檢查Docker版本3.3 檢查docker compose 版本四、下載serverMmon鏡像五、…

力扣刷題(數組篇)

日期類 #pragma once#include <iostream> #include <assert.h> using namespace std;class Date { public:// 構造會頻繁調用&#xff0c;所以直接放在類里面&#xff08;類里面的成員函數默認為內聯&#xff09;Date(int year 1, int month 1, int day 1)//構…

【通縮螺旋的深度解析與科技破局路徑】

通縮螺旋的深度解析與科技破局路徑 一、通縮螺旋的形成機制與惡性循環 通縮螺旋&#xff08;Deflationary Spiral&#xff09;是經濟學中描述價格持續下跌與經濟衰退相互強化的動態過程&#xff0c;其核心邏輯可拆解為以下鏈條&#xff1a; 需求端萎縮&#xff1a;居民消費信…

單一責任原則在Java設計模式中的深度解析

在軟件開發中&#xff0c;設計模式提供了一種解決特定問題的思路。在眾多的設計原則中&#xff0c;單一責任原則&#xff08;Single Responsibility Principle&#xff0c;SRP&#xff09;是一個非常重要的概念。它主要強調一個類應該只有一個責任&#xff0c;也就是說&#xf…

開源后臺管理系統推薦

前言 在當今數字化時代&#xff0c;企業和組織對于管理和運營資源的需求日益增加。開源后臺管理系統應運而生&#xff0c;為用戶提供了一個靈活、可定制化的管理平臺。本文將介紹開源后臺管理系統的概念和優勢&#xff0c;探討常見的開源后臺管理系統&#xff0c;以及如何選擇…

原生微信小程序實現導航漫游(Tour)

效果&#xff1a; 小程序實現導航漫游 1、組件 miniprogram/components/tour/index.wxml <!--wxml--> <view class"guide" wx:if"{{showGuide}}"><view style"{{guideStyle}}" class"guide-box"><view class&quo…

Docker容器命令速查表

這是 Docker 的快速參考備忘單。 你可以在這里找到最常見的 Docker 命令。 安裝 curl -sSL https://get.docker.com/ | sh sudo chmod 777 /var/run/docker.sock在后臺創建和運行容器 $ docker run -d -p 80:80 docker/getting-started-d - 以分離&#xff08;后臺&#xff0…

Qt QML實現鼠標自由選擇不規則區域進行截圖

背景 不規則區域進行截圖是一種常見的應用場景&#xff0c;通常用于程序截圖工具或者圖像處理軟件中。主要是為了讓用戶可以自由選擇任意形狀的區域進行截圖&#xff0c;而不僅僅局限于矩形區域。這樣用戶可以更靈活地進行截圖操作&#xff0c;特別是對于需要截取特定形狀區域…