最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會(huì)員登陸 & 注冊(cè)

C#實(shí)際案例分析(第四彈)——By 流星

2021-11-17 14:55 作者:ForeverMeteor  | 我要投稿

實(shí)驗(yàn)四

題目要求

仿照windows的文件瀏覽器,編寫一個(gè)樹狀視圖的文件瀏覽器

環(huán)境設(shè)置

操作系統(tǒng): Windows 10 x64

SDK: .NET Framework 4.7.2

IDE: Visual Studio 2019


題意分析

我們這一次要來寫文件瀏覽器。在現(xiàn)在的Windows圖形化界面中,先前的列表式或是樹狀的文件瀏覽器已經(jīng)較為少見了。不過他們的原理和結(jié)構(gòu)也還算相對(duì)簡單,我們將在下面進(jìn)行解析。

參照現(xiàn)有的Windows系統(tǒng),該文件瀏覽器應(yīng)該具有以下幾個(gè)功能和附加功能:

基本功能:
① 打開某一指定目錄
② 展示該目錄下的所有文件/文件夾
③ 對(duì)于該目錄下的每一個(gè)文件夾,能夠遞歸進(jìn)行①②③直至某空文件夾或是某個(gè)文件夾下全是文件
④ 能夠返回上級(jí)目錄,再進(jìn)行①②③
⑤ 在某一具象化的數(shù)據(jù)結(jié)構(gòu)中進(jìn)行文件和文件夾的展示

附加功能:
⑥ 能夠在窗體中打開某一應(yīng)用窗口或文件夾窗口
⑦ 文件夾樹的全展開

羅列出來的這些功能也正是我們要實(shí)現(xiàn)這個(gè)應(yīng)用的思路?;竟δ芪覀兙ㄟ^調(diào)用C#提供的TreeView控件和文件讀取的功能來實(shí)現(xiàn)。這里注意③中的遞歸訪問,是在系統(tǒng)的文件操作中非常重要的一個(gè)思想,我們將在接下來的代碼解析部分詳細(xì)解讀。附加功能⑦依然通過調(diào)用TreeView的功能來實(shí)現(xiàn),而⑥就要通過調(diào)用系統(tǒng)進(jìn)程的功能了。

筆者開發(fā)的窗體中,最初始的路徑通過用戶輸入得到(當(dāng)然也可以通過OpenDialog窗口來實(shí)現(xiàn)),之后在TreeView中顯示路徑下的子文件和子文件夾。通過右上角的兩個(gè)按鈕來實(shí)現(xiàn)樹的展開/收縮。同時(shí),在選定的某一結(jié)點(diǎn)做根結(jié)點(diǎn)的情況下,在左側(cè)的ListBox中顯示它的孩子。最終開發(fā)的窗體界面如下:

最終窗體的形態(tài)

數(shù)據(jù)結(jié)構(gòu)·文件樹

數(shù)據(jù)結(jié)構(gòu)中的在計(jì)算機(jī)中的應(yīng)用非常普遍,例如求表達(dá)式值,哈夫曼編碼等。在生活中的應(yīng)用也非常普遍,例如本篇文章的組織結(jié)構(gòu)也是樹:

文章的組織結(jié)構(gòu)

操作系統(tǒng)中的文件目錄也是通過樹來組織的。例如早期的界面:

文件樹(早期操作系統(tǒng))

其中,文件就是葉子結(jié)點(diǎn),而文件夾就是根結(jié)點(diǎn)內(nèi)部結(jié)點(diǎn)?;蛘?,若我們將文件看作原子,將文件夾看作列表,文件的組織形式也可以看作廣義表(列表)。這兩種理解方式本質(zhì)上是一樣的。

觀察某一路徑:

最后一個(gè)"\"后面是結(jié)點(diǎn)自身(可以不是葉子),例如上述的dotnet.exe。而路徑上的其他文件夾便是它的祖宗。

通過dir指令,我們可以在DOS下查看一個(gè)結(jié)點(diǎn)的子目錄:

同時(shí),DOS也提供了tree指令來具象化地展示文件樹(但是只能展示文件夾):

綜上所述,我們可以將要訪問的路徑做根,文件、文件夾和結(jié)點(diǎn)一一對(duì)應(yīng),將其視作一棵樹來進(jìn)行處理。之后我們便可以引用樹的各種操作:建樹,遍歷,銷毀等,配合C#提供的組件來實(shí)現(xiàn)對(duì)目錄的瀏覽。下面詳細(xì)展開。


完整代碼

代碼片段分析

為了防止混亂,先貼上各個(gè)控件的分布圖:

控件分布圖


各個(gè)控件功能代碼

該事件用以完成整個(gè)文件瀏覽器最核心的內(nèi)容,即讀取,加載,展開目錄。最開始先將TreeView的內(nèi)容清空,便于展示。而最后加載完成時(shí)候使能(Enable)展開結(jié)點(diǎn)與收起結(jié)點(diǎn)的按鈕。它的核心部分是中間的FileTraverse函數(shù),我們接下來重點(diǎn)解析它。

FileTraverse函數(shù)

我們一般通過遞歸的方式去遍歷一棵樹。這里的文件訪問過程即是樹的先序遍歷(即先訪問根結(jié)點(diǎn),再依次先序遍歷各個(gè)子樹)。文件樹的遞歸出口即是該文件夾下全是文件(全為葉子結(jié)點(diǎn))或是空文件夾(自身為葉子結(jié)點(diǎn))。在這里,判斷是否為遞歸結(jié)束的標(biāo)志即是if (foldersLen == 0)。也就是說,無論文件(葉子結(jié)點(diǎn))有多少,只要沒有了文件夾,就應(yīng)該停止遞歸。在停止遞歸之前,將葉子結(jié)點(diǎn)全部加載。若非如此,則按照之前的思想,先將文件加載進(jìn)來(t.Nodes.Add(getNameWithoutRoute(files[i]))),再加載一個(gè)文件夾(t.Nodes.Add(getNameWithoutRoute(folders[i]));),并遞歸地去遍歷它(FileTraverse(folders[i], t.LastNode))。

最終實(shí)現(xiàn)的結(jié)果就是將該路徑下的全部文件都加載到了TreeView/內(nèi)存中,我們可以在之后的過程中訪問它了。遞歸思想是遍歷文件樹最核心的思想,一定要注意掌握。

我們接著往下看:

TreeView控件為我們提供了結(jié)點(diǎn)的單擊和雙擊事件(但是ListBox卻沒有對(duì)Item提供相應(yīng)的功能,這點(diǎn)筆者感到非常奇怪),我們通過調(diào)用他們來實(shí)現(xiàn)結(jié)點(diǎn)的展開和附加功能,即調(diào)用進(jìn)程。

為了方便瀏覽文件,在單擊事件中實(shí)現(xiàn)了將子目錄加載到左邊的ListBox,即一部分列表文件瀏覽器的功能。每一次加載,都需要判斷當(dāng)前單擊選定的結(jié)點(diǎn)是否為文件夾并更新全局變量isCurrentFile,以便于例如通過ListBox打開進(jìn)程等的后續(xù)操作。

在這里,為了美觀,我們使用了String類的Remove函數(shù)。該函數(shù)原型如下:
string Remove(int startIndex, int length)
若省去length而只有startIndex這一參數(shù),則默認(rèn)刪除至最后。調(diào)用傳入的事件e的ToString方法,得到的名字默認(rèn)會(huì)帶上"TreeNode ",所以我們通過Remove函數(shù)將其刪除,達(dá)到了較美觀的效果。這個(gè)函數(shù)在下面功能的實(shí)現(xiàn)仍然要用到。


雙擊事件用于附加功能-打開進(jìn)程的實(shí)現(xiàn)。當(dāng)一個(gè)子結(jié)點(diǎn)存在且沒有子結(jié)點(diǎn)時(shí)(if (e.Node.Nodes.Count == 0)),它必然是一個(gè)文件,因而我們將它的路徑拼接起來就能形成它的絕對(duì)路徑currentPath = rootPath + e.Node.FullPath.Remove(0, "當(dāng)前目錄".Length);)。其中,F(xiàn)ullpath屬性返回的是從TreeView中根結(jié)點(diǎn)出發(fā)直到自己的路徑,因而它開始附帶著根結(jié)點(diǎn)的命名,而實(shí)際情況中我們不需要它,使用Remove函數(shù)把它刪掉。在獲取絕對(duì)路徑之后,我們使用:

來調(diào)用進(jìn)程。學(xué)過Python的同學(xué)就會(huì)對(duì)這個(gè)操作感覺到非常熟悉,行云流水。它等效于以下的python代碼:

C#的功能中已經(jīng)提供了通過WinForm調(diào)用其他WinForm的功能,也就是上述的語句。詳細(xì)的底層實(shí)現(xiàn)筆者也不太清楚,需要查看對(duì)應(yīng)的文檔。不過在這個(gè)附加功能的實(shí)現(xiàn)中,我們能學(xué)會(huì)調(diào)用它就足夠了。

可以看到,雙擊事件中對(duì)于文件夾的操作自然地被過濾掉了,其原因就是它自帶了展開子結(jié)點(diǎn)的功能。

總結(jié)

實(shí)機(jī)操作過程的效果如下:

實(shí)機(jī)操作效果

通過這次實(shí)驗(yàn),我們熟悉了C#中TreeView、ListBox等控件的功能和使用。加深了對(duì)數(shù)據(jù)結(jié)構(gòu)中樹結(jié)構(gòu)的理解,并應(yīng)用它來完成文件樹的遍歷和加載。同時(shí),我們還進(jìn)一步熟悉了字符串的操作,了解了進(jìn)程調(diào)用等功能??傮w來說,這次實(shí)驗(yàn)還是較為簡單的,要注意重點(diǎn)掌握遞歸遍歷的思想。

這個(gè)應(yīng)用仍有部分缺陷,比如由于ListBox的特性,難以在列表中通過雙擊選中項(xiàng)目來打開文件。再例如,文件樹的實(shí)現(xiàn)過程是將路徑下的子文件夾下遞歸的所有子文件夾和子文件一并加載到TreeView中,也就是一次性加載到內(nèi)存中。這樣效率較低,浪費(fèi)時(shí)間,如果能在每次點(diǎn)擊結(jié)點(diǎn)的時(shí)候再進(jìn)行加載,效果就會(huì)很好了。最后,在實(shí)際操作過程中發(fā)現(xiàn)初始路徑為系統(tǒng)根目錄(即C:\)時(shí)加載出現(xiàn)問題,拋出異常,初步猜測是訪問權(quán)限的問題。

參考文獻(xiàn)

李春葆,曾平,喻丹丹.C#程序設(shè)計(jì)教程(第3版):清華大學(xué)出版社,2015

Copyright @ 2021, Bilibili: ForeverMeteor, all rights reserved.?

C#實(shí)際案例分析(第四彈)——By 流星的評(píng)論 (共 條)

分享到微博請(qǐng)遵守國家法律
西峡县| 蓝山县| 凤山市| 阿荣旗| 平度市| 玉山县| 体育| 定边县| 阜城县| 蒙城县| 平南县| 清水河县| 屏东县| 普格县| 康马县| 吐鲁番市| 乐昌市| 林周县| 拉萨市| 呼和浩特市| 永昌县| 敖汉旗| 板桥市| 华坪县| 漳州市| 利津县| 德惠市| 称多县| 关岭| 如东县| 辉南县| 长海县| 黔江区| 阿合奇县| 玉林市| 和田县| 互助| 河池市| 娄烦县| 东莞市| 庆云县|