發現我土砲的 ASP.NET 檔案同步機制有個檔案一直出現在更新清單,反覆上傳多次卻一直無法同步。老司機眉頭一皺,立刻懷疑是檔案大小寫問題。

比對了來源端與目的端檔名,證實是檔名大小寫問題無誤。來源主機原本有個檔案 Logo_TW.png,因故被刪除換成 Logo_tw.png,而目的主機留有舊版 Logo_TW.png,同步機制成功覆寫了目的主機的 Logo_TW.png 檔案內容,但檔名卻沿用原本的 Logo_TW.png。由於我是用 .NET 字串相等比對檔名,下次比對時發現目的地缺少 Logo_tw.png (只有 Logo_TW.png,但同步只有單向故不會補回來),便試圖上傳新增 Logo_tw.png,但實際上是覆寫目的主機的 Logo_TW.png,而檔名沒變(還是_TW),等到下次同步時再被抓出來處理一次。

Windows 的檔案系統不分大小寫,進行更名時,若新舊檔名相同只有大小寫有差異,則 Windows 將不會更換檔名。請看示範:

Logo_EN.png 改 Logo_TW.png 沒問題,但如果是 Logo_TW.png 改 Logo_tw.png,Windows 不會理你。

這個行為還算能被理解,但重新寫檔時也會發生類似狀況,若處理檔名時未忽略大小寫差異就會像我一樣踩到雷。

用一小段 PowerShell 程式重現問題。我先建一個 test_TW.txt,之後寫入檔案 test_tw.txt,讀取檔案內確認已有被置換,用 System.IO.Directory.GetFiles 取回檔名比對,若比對寫法有區分大小寫,就會出現檔名不吻合的狀況。

要解決這類問題,程式比對檔名時應改為不分大小寫,例如:C# string.Compare(a, b, StringComparison.CurrentCultureIgnoreCase)、ToLower() 後相比、PowerShell -eq... 等等。但如果程式會跨平台,Linux 檔案系統則大小寫有別,就要留意環境差異。

Windows case-insensitive filenaming will ignore overwriting new filename which is only different in upper/lower case.


Comments

# by Huang

字串比對的陷阱,一律先轉大寫/小寫來避免採雷

Post a comment