3 回答

TA貢獻2021條經驗 獲得超8個贊
只需檢查符號鏈接是否存在并在創建新鏈接之前將其刪除
if _, err := os.Lstat(symlinkPath); err == nil {
os.Remove(symlinkPath)
}

TA貢獻1859條經驗 獲得超6個贊
這里的其他答案是正確的......但有兩個小問題:
有一個微小的數據競爭,新的符號鏈接將在此處之前但在刪除之后的其他地方創建,使其處于潛在的不一致狀態。
如果程序在創建符號鏈接之前死亡/崩潰,但在刪除前一個符號鏈接之后,它可能會再次使事情處于不一致的狀態。
處理這個問題的更原子的方法是創建一個臨時符號鏈接,然后將其重命名為原始符號鏈接:
symlinkPathTmp := symlinkPath + ".tmp"
if err := os.Remove(symlinkPathTmp); err != nil && !os.IsNotExist(err) {
return err
}
if err := os.Symlink(filePath, symlinkPathTmp); err != nil {
return err
}
if err := os.Rename(symlinkPathTmp, symlinkPath); err != nil {
return err
}
在刪除臨時鏈接和重新創建它之間仍然存在小競爭,但它不會冒使主要鏈接處于不一致狀態的風險。理想情況下,我們可以通過為臨時鏈接使用隨機名稱來解決這個問題,但是 Go 的 TempFile 總是會創建一個新文件,因此它不是很有用。(您可以調用 TempFile,然后刪除文件名并重新使用該名稱,這會比僅附加一個常量.tmp后綴更危險但更安全。)
然而,即使有那場比賽,你仍然可以獲得原子性,任何中斷都不會導致丟失鏈接。
請注意,這取決于 Posix 行為,并且可能無法在 Windows 上運行(為什么還要在 Windows 上使用符號鏈接?),但它是許多需要原子符號鏈接替換的 macOS/Linux 工具共享的技術。

TA貢獻1868條經驗 獲得超4個贊
請注意,@Vadyus 的答案在運行 lstat 時隱藏了實際的文件系統錯誤。例如,如果您的磁盤損壞并且 Lstat 失敗,您仍然會運行 os.Remove 并忽略它的錯誤(危險,除非您喜歡調試幾個小時)。
以下片段正確檢查文件是否存在和其他錯誤:
if _, err := os.Lstat(symlinkPath); err == nil {
if err := os.Remove(symlinkPath); err != nil {
return fmt.Errorf("failed to unlink: %+v", err)
}
} else if os.IsNotExist(err) {
return fmt.Errorf("failed to check symlink: %+v", err)
}
- 3 回答
- 0 關注
- 179 瀏覽
添加回答
舉報