這是上週遇到的問題,我們有個專案參與開發的人比較多,一直以來都用 TFS 進行版本控管與專案管理,一直以來專案在本機開發環境執行的時候都沒遇到過任何問題,但突然有一天所有團隊成員都發生無法讀取特定檔案的問題 ( Access to the path 'C:\Inetpub\wwwroot\App_Data\TEST.txt' is denied ),查到了程式碼發現是在呼叫 File.Open 時發生的錯誤,但檔案權限明明就沒有問題啊!問題要如何解決,請繼續看下去…
由於錯誤訊息是【Access to the path 'C:\Inetpub\wwwroot\App_Data\TEST.txt' is denied.】,當我得知這個問題後也是先往「安全性」的角度出發進行查看,但即便該檔案都設定 Everyone 完全控制了,還是引發例外,因此必須往其他角度思考。
接著我進一步透過 Process Monitor 察看我的程式到底在開啟這個檔案時到底有哪些資訊可查,結果發現也看不出有什麼異狀,基本上我們的程式單純的只是把檔案開啟、讀取內容、關閉檔案這樣子而已,不知為何有那麼多問題,而詭異的是當下一群人都不知道為什麼程式好好的跑了半年,卻突然有一天所有人的開發環境都掛了,只有部署上架的程式沒問題而已。
解決問題需要創意與跳躍式思考,我後來看見該檔案有個異常的狀況,那就是檔案屬性是「唯讀」的!
當我把檔案的唯讀屬性取消掉之後,所有問題自然迎刃而解,最後才去找出證明這個問題發生的主因,我第一個想到的是從 MSDN 的文件著手,發現 File.Open 方法 有三個多載,一般來說我們為了方便都會用第一個 File.Open 方法 (String, FileMode),不過使用這個方法時當開啟的檔案是唯讀的時候就會引發 UnauthorizedAccessException 例外,這可是天大的發現,因為我們前幾年都是用 Subversion 當作版本控管工具,並沒有唯讀檔案的問題,所以也一直不知道 TFS 會有這個問題。
但是我們這個專案用 TFS 也一段時間了,直到最近才發生問題才有鬼了,原來是我們要用 File.Open 開啟的檔案放在 App_Data 裡,而這些檔案是寄送電子郵件的郵件內容範本(Template),而在開發環境時寄信功能是關閉的,所以一直沒有人發現有此問題,直到最近開發環境的郵件功能被打開了(而且程式也簽入 TFS 版本庫),因此只要執行到寄信的功能就會在開啟這些檔案時掛掉!
最後的結論是:TFS 版本控管時會將檔案設為唯讀,在使用 .NET 的 File.Open 開啟檔案時會發生 UnauthorizedAccessException 例外,所以在開發環境使用時必須將檔案簽出(讓檔案變成可讀寫),或是修改程式讓你的 .NET 程式可以讀取唯讀檔案的資料 (建議作法)。
不過這樣一個簡單的結論卻是經過一段辛苦的追查得知的,當然,如果你今天要開啟檔案時真的只需要讀取資料而已的話,可以用 File.Open 方法 (String, FileMode, FileAccess) 來完成,並指派適當的 FileAccess 值,如下範例:
using (FileStream fs = File.Open(filePath, FileMode.Open, FileAccess.Read))
{
}
相關連結