(原創(chuàng))[C#]一步步解決DotNetZip因超長路徑(MAX_PATH)報(bào)錯(cuò)的問題。
一、前言
超長路徑(MAX_PATH)的問題,在很多地方都可能遇到,常見的解決辦法無非三種:添加前綴\\?\、app.config添加配置、修改注冊表等。
而對于其它第三方的DLL,我們?nèi)绾稳耐獠拷鉀Q呢?答案是:反射。
本篇文章,我們就以DotNetZip為例,一步步來解決超長路徑的問題。
**相信看完的你,一定會有所收獲!
**
本文地址:http://www.rzrgm.cn/lesliexin/p/18930533
二、一步步定位問題
首先,我們看下使用DotNetZip的ZipEntry.AddDictionary()方法添加一個(gè)目錄后,相關(guān)屬性的變化。

我們可以看到,在添加前,ZipFile.Entries是空的。
在添加后,變化如下:

會遇到超長路徑(MAX_PATH)報(bào)錯(cuò),肯定會有一個(gè)完整的路徑,當(dāng)然存在臨時(shí)拼接的情況,但是我們先找一找。
最后,我們在“非公開成員”中找到一個(gè)屬性:LocalFileName,其值正是完整的文件路徑,如下圖所示:

為了方便觀察,我們將LocalFileName屬性置頂顯示:

之后我們就可以看到,默認(rèn)顯示的都是LocalFileName了:

現(xiàn)在我們找到這個(gè)關(guān)鍵的LocalFileName,雖然還不能百分百確定和這有關(guān),但是可以以此為準(zhǔn)進(jìn)行后面的排查和驗(yàn)證了。
三、反編譯梳理邏輯
像DotNetZip,是開源的,我們可以直接找到源碼來查看,對于非開源的,我們就只能反編譯了。
這里常用的工具是dnSpy,我們使用dnSpy打開DotNetZip,然后定位到ZipEntry,再找到LocalFileName屬性:

可以看到只有g(shù)et,沒有set,這樣的話,如果直接反射操作此屬性,則需要額外的添加set訪問器,非常麻煩,此時(shí)不作考慮。
我們再看,LocalFileName其實(shí)是返回的變量:_LocalFileName,我們再找下此變量:

這樣的話就簡單了,我們反射直接操作此變量:

我們在處理時(shí),先進(jìn)行判斷是否超長,再反射處理,因?yàn)榉瓷涫呛芎馁Y源的。
至于擴(kuò)展方法,定義如下:

說一下這里面為什么要以248作為判斷條件,是因?yàn)?60是文件路徑限制,而對于目錄則是以248為限制,所以我們以最小的為主進(jìn)行判斷。
四、驗(yàn)證
這里就不貼圖了,驗(yàn)證發(fā)現(xiàn)已經(jīng)可以正常處理超長路徑了,不會再報(bào)錯(cuò)了。
在解決此問題時(shí),其實(shí)也是會捋一下相關(guān)的代碼邏輯的,看看是不是真的只處理此變量就行了,只是本次這個(gè)很確定,再捋代碼流程也沒必要,也不是本文的重點(diǎn),就不再贅述了。
五、開源
因?yàn)镈otNetZip已經(jīng)不再積極維護(hù),且Nuget上的版本也標(biāo)記了棄用和風(fēng)險(xiǎn),所以也就不提PR了,
但在這么多壓縮解壓縮庫中,DotNetZip在易用性上是無與倫比的,所以在很多時(shí)候用用還是挺不錯(cuò)的。也基于此想法,正好也將自己之前封裝的方法給開源了吧,基于DotNetZip,就兩個(gè)方法:Zip、UnZip。簡單易用、解決了超長路徑(MAX_PATH)問題、支持密碼、分卷。
開源地址:https://gitee.com/lesliexin/lesliexin.simplezip
NuGet:https://www.nuget.org/packages/LeslieXin.SimpleZip
六、結(jié)語
這次也是遇到了這個(gè)超長路徑(MAX_PATH)的問題,才想起來修復(fù)下,順便也開源下自己的庫。
本篇文章最重要的是給讀者一個(gè)遇到超長路徑(MAX_PATH)問題時(shí)一個(gè)實(shí)操指導(dǎo),畢竟此問題不止會發(fā)生在DotNetZip中,可能發(fā)生在任何與文件路徑相關(guān)的地方,當(dāng)再次遇到此問題時(shí),該如何一步步去排查定位和處理。
感謝大家的觀看,本人水平有限,文章不足之處歡迎大家評論指正。
-[END]-

浙公網(wǎng)安備 33010602011771號