今天在設計檔案 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 的問題發生。