簡體   English   中英

將使用System.IO.StreamWriter和WriteLineAsync等待另一個線程正在訪問的文件

[英]Will using System.IO.StreamWriter & WriteLineAsync wait for a file that is being accessed by another thread

我的asp.net mvc-5網絡應用程序中包含以下代碼:-

System.IO.StreamWriter file =
new System.IO.StreamWriter(Server.MapPath("~/logs/logs.txt"), true);
await file.WriteLineAsync("execution started at " + System.DateTime.Now.ToString());
file.Close();

現在我的問題是,如果兩個方法同時執行上述代碼,將會發生什么? 其中之一會失敗嗎? 因為它將嘗試寫入另一個線程正在訪問的txt文件?

您可以利用TPL Dataflow為您很好地做到這一點,從而獲得一個隊列和一種機制,通過該機制,不會並行發生對文件的寫入(通過使用MaxDegreeOfParallelism

public class Logger
{
    private ActionBlock<string> block;
    public Logger(string filePath)
    {
        block = new ActionBlock<string>(async message => {
            using(var f = File.Open(filePath, FileMode.OpenOrCreate, FileAccess.Write))
            {
                f.Position = f.Length;
                using(var sw = new StreamWriter(f))
                {
                    await sw.WriteLineAsync(message);
                }
            }
        }, new ExecutionDataflowBlockOptions{MaxDegreeOfParallelism = 1});
    }
    public void Log(string message)
    {
        block.Post(message);
    }
}

當您使用字符串打開StreamWriter它將執行以下操作來創建流

private static Stream CreateFile(String path, bool append, bool checkHost) {
    FileMode mode = append? FileMode.Append: FileMode.Create;
    FileStream f = new FileStream(path, mode, FileAccess.Write, FileShare.Read,
        DefaultFileStreamBufferSize, FileOptions.SequentialScan, Path.GetFileName(path), false, false, checkHost);
    return f;
}

因為FileAccess.Write, FileShare.Read確實執行FileAccess.Write, FileShare.Read所以它正在請求寫入權限,並且僅在其他人要求讀取權限的情況下才允許其他人打開文件。 因為兩個調用都將要求寫許可,所以第二個調用將失敗,並顯示“正在使用文件”錯誤。


解決此問題的一種方法是使用SemaphoreSlim阻止對文件的訪問,這一次只能允許一個編寫者。

//Elsewhere
private static SemaphoreSlim _fileLock = new SemaphoreSlim(1);


//In your function.
try
{
    await _fileLock.WaitAsync();
    using(var file = new System.IO.StreamWriter(Server.MapPath("~/logs/logs.txt"), true))
    {
        await file.WriteLineAsync("execution started at " + System.DateTime.Now.ToString());
    }
}
finally
{
    _fileLock.Release();
}

但是,更好的解決方案是找到一個可以像Log4Net那樣為您處理此事的第三方日志庫,那么您就不必擔心鎖定或並發了。

是。 您將收到一個錯誤,指出該文件正在被另一個進程使用。 最好的選擇是用try catch包圍該塊並處理異常,然后在文件可用時重試。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM