将使用System.IO.StreamWriter&;WriteLineAsync等待另一个线程正在访问的文件
本文关键字:线程 另一个 等待 文件 访问 WriteLineAsync System IO StreamWriter amp | 更新日期: 2023-09-27 17:58:00
我的asp.net mvc-5 web应用程序中有以下代码:-
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数据流来实现这一点,这样您就可以获得一个队列和一种机制,通过该机制,对文件的写入永远不会并行发生(通过使用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
,这意味着它请求写入权限,并且只允许其他人在请求读取权限时打开文件。因为两个调用都将请求写入权限,所以第二个调用将失败,并出现"文件正在使用"错误。
解决这个问题的一种方法是使用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
包围该块并处理异常,然后在文件可用后重试。