我正在尝试实现锁定场景,其中多个线程同时或在不同时间访问同一文件。在测试时,代码似乎覆盖现有的行而不是追加新的行。
namespace SMPPService
{
public static class LogFile
{
public static void WriteErrorLog(Exception ex)
{
byte[] buf = GetBytes(DateTime.Now.ToString() + ": " + ex.Source.ToString().Trim() + "; " + ex.Message.ToString().Trim());
Lock(HttpRuntime.AppDomainAppPath + "\\Exceptions.txt",
(f) =>
{
try
{
f.Write(buf, 0, buf.Length);
}
catch (IOException ioe)
{
// handle IOException
}
}, buf);
}
public static void WriteErrorLog(string Message)
{
byte[] buf = GetBytes(DateTime.Now.ToString() + ": " + Message);
Lock(HttpRuntime.AppDomainAppPath + "\\LogFile.txt",
(f) =>
{
try
{
f.Write(buf, 0, buf.Length);
}
catch (IOException ioe)
{
// handle IOException
}
}, buf);
System.Threading.Thread.Sleep(60000);
}
public static void Lock(string path, Action<FileStream> action,byte [] lines)
{
var autoResetEvent = new AutoResetEvent(false);
while (true)
{
try
{
using (var file = File.Open(path,
FileMode.OpenOrCreate,
FileAccess.ReadWrite,
FileShare.Write))
{
action(file);
break;
}
}
catch (IOException)
{
var fileSystemWatcher =
new FileSystemWatcher(Path.GetDirectoryName(path))
{
EnableRaisingEvents = true
};
fileSystemWatcher.Changed +=
(o, e) =>
{
if (Path.GetFullPath(e.FullPath) == Path.GetFullPath(path))
{
autoResetEvent.Set();
}
};
autoResetEvent.WaitOne();
}
}
}
static byte[] GetBytes(string str)
{
byte[] bytes = new byte[str.Length * sizeof(char)];
System.Buffer.BlockCopy(str.ToCharArray(), 0, bytes, 0, bytes.Length);
return bytes;
}
}
}
用法
LogFile.WriteErrorLog("Requesting SMPP Client from WMAS..." + " " + "Date:" + DateTime.Now + " " + "Source Address:" + msisdn);
答案 0 :(得分:0)
FileShare.Write
来自MSDN:
允许随后打开文件进行书写。
这正是您不想使用的旗帜。对于文件,最简单的锁定方法是让文件系统为您执行此操作,使用FileShare.Read
(以便有人可以查看日志),如果打开失败则重试共享违规。
实现你自己的锁定只会在文件系统已经存在的情况下重新创建,但很糟糕。
此外,而不是自己处理编码(使边缘情况正确并不容易):
StreanWriter
的构造函数有一个超载来执行此操作。
编辑:快速检查reference source:这确实使用FileShare.Read
。
答案 1 :(得分:0)
您应该使用File.AppendAllLines代替您的lock
方法。 File.AppendAllLines 不线程安全,您必须将其锁定。
private object lockObject = new object();
private string fileName = Path.Combine(HttpRuntime.AppDomainAppPath, "LogFile.txt");
public static void WriteErrorLog(string Message)
{
lock(lockObject)
{
File.AppendAllLines(fileName, new string[] { Message + "\n" });
}
}
请注意{。3}}是在.Net 4中引入的,你必须在旧框架中使用File.AppendAllLines