golang如何判斷文件是否存在
判斷一個文件是否存在是一個相當(dāng)常見的需求,在golang中也有多種方案實現(xiàn)這一功能。
現(xiàn)在我們介紹其中兩種最常用也是最簡單的實現(xiàn),第一種將是跨平臺通用的,而第二種則在POSIX平臺上通用。
跨平臺實現(xiàn)
跨平臺實現(xiàn)的思路很簡單,如果某個文件不存在,那么使用os.Lstat
就一定會返回error,只要判斷error是否代表文件不存在即可。
也許你注意到了有些代碼會使用os.Open
來完成上述工作,不過最好不要這么做,因為雖然兩者完成的功能沒有區(qū)別,但open和stat的調(diào)用開銷是不同的,后者要小于前者,而且對于判斷文件是否存在,檢查它的元數(shù)據(jù)要比直接嘗試打開它更加合理。
那么來看看實現(xiàn)的代碼:
func FileExist(path string) bool { _, err := os.Lstat(path) return !os.IsNotExist(err) }
代碼很簡單,對于Windows/Linux/MacOS等是通用的,一般沒有特殊需求我也比較推薦這種實現(xiàn)。
POSIX平臺實現(xiàn)
如果你的程序是面向POSIX平臺的(例如UNIX、Linux等),那么還有一種更簡單的方案——syscall.Access
。
syscall.Access
提供了用戶檢查文件元信息的手段,通常它被用來檢查文件權(quán)限以及文件的存在性。
通過使用syscall.F_OK
標(biāo)志檢查文件,如果不存在則會返回和os.Lstat
一樣的error:
func FileExist(path string) bool { err := syscall.Access(path, syscall.F_OK) return !os.IsNotExist(err) }
這種實現(xiàn)的最大優(yōu)勢在于它簡單而直觀,但是它無法在Windows上使用。
一些提示
首先當(dāng)我們的FileExist
返回true時,其實文件并不一定存在。
當(dāng)我們對目標(biāo)path中的某一部分沒有可讀權(quán)限時,os.Lstat
和syscall.Access
同樣會返回error,不過這個error不會讓os.IsNotExist
返回true。
當(dāng)文件不存在而你對文件所在的目錄或者它的上層目錄沒有訪問權(quán)限時,FileExist
依舊會返回true,bug就在這時發(fā)生了。所以重要的一點是在判斷文件是否存在前應(yīng)該先判斷自己對文件及其路徑是否有訪問權(quán)限。
其次syscall.Access
只會使用運行程序的用戶的uid和gid,這會導(dǎo)致setuid之類的權(quán)限失效,通常來說這是沒什么問題的,然而posix平臺上一般都會考慮euid和egid,因此你可能需要使用syscall.Faccessat
做代替。你需要在深思熟慮后使用合適的系統(tǒng)調(diào)用。
性能測試
最后我們看看兩個方案的性能,我們以os.Open
做為基準(zhǔn),分別測試先文件存在和不存在時的性能表現(xiàn):
func checkWithOpen(path string) bool { f, err := os.Open(path) if err != nil { return false } f.Close() return true } func checkWithLstat(path string) bool { _, err := os.Lstat(path) return !os.IsNotExist(err) } func checkWithAccess(path string) bool { err := syscall.Access(path, syscall.F_OK) return !os.IsNotExist(err) } func BenchmarkNotExists(b *testing.B) { for range b.N { checkWithOpen("/home/apocelipes/no-") } } func BenchmarkNotExistsLstat(b *testing.B) { for range b.N { checkWithLstat("/home/apocelipes/no-") } } func BenchmarkNotExistsAccess(b *testing.B) { for range b.N { checkWithAccess("/home/apocelipes/no-") } } func BenchmarkExists(b *testing.B) { for range b.N { checkWithOpen("/home/apocelipes/.zshrc") } } func BenchmarkExistsLstat(b *testing.B) { for range b.N { checkWithLstat("/home/apocelipes/.zshrc") } } func BenchmarkExistsAccess(b *testing.B) { for range b.N { checkWithAccess("/home/apocelipes/.zshrc") } }
這是結(jié)果:
測試使用的文件系統(tǒng)類型是XFS。
可以看到open是最慢的,lstat比access慢了16%左右。從結(jié)果里也可以看到lstat需要額外返回一個os.FileInfo
結(jié)構(gòu)導(dǎo)致了額外的內(nèi)存分配,所以整體上速度更慢。
但考慮到跨平臺以及兼容性,使用os.Lstat
是更常見的做法。
以上就是golang如何判斷文件是否存在的詳細內(nèi)容,更多關(guān)于go判斷文件是否存在的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Go?Excelize?API源碼解析GetSheetFormatPr使用示例
這篇文章主要為大家介紹了Go?Excelize?API源碼解析GetSheetFormatPr使用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-08-08