我有两个程序:一个C#GUI应用程序和一个访问同一文本文件的C#windows服务;
a) the C# GUI application will write/append to the text file
b) the windows service will copy the file to a network location every 20 mins.
当动作同时发生时,我收到如下错误消息:
2014/09/08 21:15:56 mscorlib
The process cannot access the file 'C:\09082014.log' because it is being used by another process.
at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy)
at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, FileOptions options)
at System.IO.StreamWriter.CreateFile(String path, Boolean append)
at System.IO.StreamWriter..ctor(String path, Boolean append, Encoding encoding, Int32 bufferSize)
at System.IO.StreamWriter..ctor(String path, Boolean append)
at DataloggerUI.DataHelper.WriteDataLog(String msg, Int64& downTimeSince)
at DataloggerUI.Form1.ReceiveData(IAsyncResult asyncResult)
---- C#windows服务部分如下所示----------
if (File.Exists(destination + @"\" + fi.Name))
{
FileInfo fi_dest = new FileInfo(destination + @"\" + fi.Name);
if (fi.LastWriteTime > fi_dest.LastWriteTime)
{
File.Copy(fi.FullName, destination + @"\" + fi.Name, true);
WriteLog("Send " + fi.FullName + " to server");
}
}
else
{
File.Copy(fi.FullName, destination + @"\" + fi.Name, true);
WriteLog("Send " + fi.FullName + " to server");
}
}
------- C#windows GUI应用程序代码如下-------
string logfile = DataHelper.GetAppConfigString("MPRS_LogDir") + @"\" + DateTime.Now.ToString("MMddyyyy") + ".log";
using (StreamWriter sw = new StreamWriter(logfile, true))
{
sw.WriteLine(tick + " " + "KYEC" + Environment.MachineName + " " + msg);
sw.Close();
}
GUI应用程序抛出错误消息。 我的代码中是否有任何错误或不良做法?
------------按照彼得的建议修改代码--------------
try
{
using (StreamWriter sw = new StreamWriter(logfile, true))
{
sw.WriteLine(tick + " " + "KYEC" + Environment.MachineName + " " + msg);
}
}
catch (IOException ex)
{
WriteErrorLog("IOException " + ex.Message);
System.Threading.Thread.Sleep(2000); //2 secs
using (StreamWriter sw = new StreamWriter(logfile, true))
{
sw.WriteLine(tick + " " + "KYEC" + Environment.MachineName + " " + msg);
}
}
答案 0 :(得分:5)
您可以在Shared ReadWrite模式下使用FileStream同时写入和复制文件。
请尝试以下代码:
//To write file use
using (FileStream fs = new FileStream(fileToReadPath, FileMode.Append, FileAccess.Write, FileShare.ReadWrite))
{
using (StreamWriter StreamWriter = new StreamWriter(fs))
{
StreamWriter.WriteLine(tick + " " + "KYEC" + Environment.MachineName + " " + msg);
StreamWriter.Close();
}
}
//To copy file use
using (FileStream inStream = new FileStream(fileToReadPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
using (FileStream outStream = File.Create(fileToWritePath))
{
while (inStream.Position < inStream.Length)
{
outStream.WriteByte((byte)inStream.ReadByte());
}
}
}
通过这种方式,您可以完成任务而不会被其他进程错误使用。
答案 1 :(得分:3)
基于Peter Duniho's answer和您自己的编辑,这应该是正确的方法:
// try to write maximum of 3 times
var maxRetry = 3;
for (int retry = 0; retry < maxRetry; retry++)
{
try
{
using (StreamWriter sw = new StreamWriter(logfile, true))
{
sw.WriteLine("{0} KYEC{1} {2}", tick, Environment.MachineName, msg);
break; // you were successfull so leave the retry loop
}
}
catch (IOException)
{
if(retry < maxRetry - 1)
{
System.Threading.Thread.Sleep(2000); // Wait some time before retry (2 secs)
}
else
{
// handle unsuccessfull write attempts or just ignore.
}
}
}
这使您有机会指定重试写入尝试的时间。
答案 2 :(得分:1)
这里至少有几个选项。最简单的概念是将文件I / O包装在try / catch中,如果发生IOException(并且仅在发生IOException时),请暂时延迟操作(例如Thread.Sleep(),设置计时器),然后再试一次
另一种方法是使用命名的互斥锁来允许服务和GUI进程协调访问。每个人在尝试各自的操作之前都会获得互斥锁;如果另一个当前正在访问该文件,那么获取互斥锁的尝试将导致进程等待另一个完成。
重试代码有时会变得混乱和冗长,所以当我认为重试方法更容易理解时,恕我直言,互斥方法实际上更容易理解,更简单正确(一旦你&#39;已经麻烦地学习如何创建一个命名的互斥体......它并不难,MSDN也有例子。)