今天在設計檔案 Lock 機制的時候,發現了一個好物 SpinWait
可以用,比起 Thread.Sleep()
+ While(true)
更來的方便效能也較佳。
多條執行續存取相同檔案時,基本要注意的事情如下:
- 我讀取檔案時,允許他人讀取不允許寫入。
- 我寫入檔案時,不允許他人讀寫。
這邊我設計了一個 FileHandler
來處理這件事情,程式碼如下:
public class FileHandler { public void WriteFileContent(string content) { using (var fs = waitFileForUse(FileAccess.Write, FileShare.None)) { fs.SetLength(0); using (var sw = new StreamWriter(fs, Encoding.UTF8)) { sw.Write(content); } } } public string ReadFileContent() { using (var fs = waitFileForUse(FileAccess.Read, FileShare.Read)) { using (var sr = new StreamReader(fs, Encoding.UTF8)) { return sr.ReadToEnd(); } } } private FileStream waitFileForUse(FileAccess fileAccess, FileShare fileShare) { const int maxRetryMilliseconds = 5 * 1000; string filePath = "note.json"; FileStream fs = null; SpinWait.SpinUntil(() => { try { fs = new FileStream(filePath, FileMode.OpenOrCreate, fileAccess, fileShare); } catch { } return (fs != null); }, maxRetryMilliseconds); if (fs == null) { throw new IOException($"無法開啟 {filePath}, 已超過 {maxRetryMilliseconds} ms 重試上限"); } return fs; } }
waitFileForUse
這個 Method 裡面我使用了 SpinWait
來去判斷檔案是否可以存取,並設定 Timeout 秒數避免 Deadlock 的問題發生。