[C#] File.Create 鎖定檔案

  • 16968
  • 0
  • C#
  • 2016-10-21

由於很久沒有寫Stream.IO 的相關程式,剛好今天有一個需求是Parser 文件,「判斷檔案是否存在,不存在就建立新的檔案,存在就寫檔」,

結果碰到一個寫檔入門常見的錯誤,

類型 'System.IO.IOException' 的未處理例外狀況發生於 mscorlib.dll 其他資訊: 由於另一個處理序正在使用檔案 'C:\Users\Administrator\Desktop\xxxx.xml',所以無法存取該檔案。

直覺反應這是串流沒有被正常關閉,導致另一個串流想要IO的時候被Lock 住了。

程式範例:

//檔案路徑
string filePath = string.Format("{0}\\{1}.xml", Directory.GetCurrentDirectory(), DateTime.Now.ToString("HH-mm-ss"));
//判斷檔案是否存在,不存在就開一個新檔案
if (!File.Exists(filePath))
{
    File.Create(filePath);
}
//開始寫檔
using (StreamWriter sw = new StreamWriter(filePath))
{
    sw.WriteLine("寫檔成功");
}

看起來很直覺,且還有使用好寫法「[C#] using statement(陳述式) 資源(IO)控管好寫法!」,

但為何會出現'System.IO.IOException',而且神奇的是“檔名”固定的條件下,程式重開後就不會有這個錯誤了!

依據這個線索,發現有問題的是File.Create()官方文件有寫道 File.Create() 後會回傳 FileStream,

也就是說,若你沒有接住這個FileStream ,在程式執行期間,這個資源是被Lock住的;換句話說,因為你沒接住這個FileStream,你也無法操控它並且釋放。

應改用以下寫法:

//檔案路徑
string filePath = string.Format("{0}\\{1}.xml", Directory.GetCurrentDirectory(), DateTime.Now.ToString("HH-mm-ss"));
//判斷檔案是否存在,不存在就開一個新檔案
if (!File.Exists(filePath))
{
    using (FileStream fs = File.Create(filePath))
    {                    
    }
}
//開始寫檔
using (StreamWriter sw = new StreamWriter(filePath))
{
    sw.WriteLine("寫檔成功");
}

或是:

//檔案路徑
string filePath = string.Format("{0}\\{1}.xml", Directory.GetCurrentDirectory(), DateTime.Now.ToString("HH-mm-ss"));
//判斷檔案是否存在,不存在就開一個新檔案
if (!File.Exists(filePath))
{
    File.Create(filePath).Close();
}
//開始寫檔
using (StreamWriter sw = new StreamWriter(filePath))
{
    sw.WriteLine("寫檔成功");
}

另外,大家應該可以發現,上述的程式碼都有使用 StreamWriter

其實很像從頭到尾,都不需要使用File.Create()來開新檔案,StreamWriter 本上就會判斷檔案是否存在,不存在就建立新的檔案,

所以程式法簡略成這樣即可:

//檔案路徑
string filePath = string.Format("{0}\\{1}.xml", Directory.GetCurrentDirectory(), DateTime.Now.ToString("HH-mm-ss"));
//開始寫檔
using (StreamWriter sw = new StreamWriter(filePath,true))
{
    sw.WriteLine("寫檔成功");
}

所以還是套一句老話,用任何工具之前請先熟悉他。