[英]Sharing network files for writing and reading
我在C#.NET 3.5中开发了客户端服务器应用程序。 该应用程序使用3个程序来完成所需的工作。 进程A(服务器)和进程B(远程启动器)是在.NET中开发的,进程C是第三方控制台应用程序,其开发语言未知。 使用远程计算机的管理凭据,进程A在其上复制进程B,并将进程B安排为远程计算机上的任务。 此后,进程B由任务计划程序启动,并创建log.txt
文件来记录消息。 然后,进程B使用Process.Start()
语义启动进程C,并重定向其standard output and error
以写入log.txt
文件。 进程A使用Process.GetProcesses(remotecomputername)
语义来监视进程C是否仍在远程计算机上运行。 进程A还使用网络共享读取\\\\RemoteComputerName\\C$\\RemoteDir\\log.txt
读取log.txt
文件,并在其窗口中显示消息。
我的问题是,所有输出和错误都未登录到log.txt
。 并且进程A无法从log.txt
正确读取。 如果使用DebugView记录了输出/错误,则说明它们已正确记录。是否存在同步/访问权限问题? 如何摆脱它? 任何指针/提示将是真正有价值的。 由于限制,无法共享完整代码。
下面给出示例代码
工序A
//Below method is called every 2 seconds from Server to read new messages.
//path passed as `\\RemoteComputerName\C$\RemoteDir\log.txt`
private void ReadRemoteLog(string path)
{
try
{
string[] lines = File.ReadAllLines(path);
while (RemoteLogPosition < lines.LongLength)
{
string msg = lines[RemoteLogPosition].Trim();
if (!string.IsNullOrEmpty(msg))
{
Trace.WriteLine("# " +msg); //Writing on DebugView
OnProgressChanged(msg);
}
RemoteLogPosition++; //This is global variable to keep track of last read position.
}
}
}
流程B的代码,用于启动流程C
ProcessStartInfo ps = new ProcessStartInfo();
ps.UseShellExecute = false;
ps.FileName = <Path to process C>;
ps.Arguments = <Commandline args to Process C>;
ps.WorkingDirectory = @"C:\RemoteDir";
ps.RedirectStandardError = true;
ps.RedirectStandardOutput = true;
Process p = new Process();
p.StartInfo = ps;
p.OutputDataReceived += (s, e) => { WriteLog(e.Data.Trim());};
p.ErrorDataReceived += (s, e) => { WriteLog(e.Data.Trim()); };
p.Start();
p.BeginOutputReadLine();
p.BeginErrorReadLine();
WriteLog("Process Started - "+ps.FileName + ps.Arguments);
p.WaitForExit();
进程B的WriteLog方法-
private void WriteLog(string message)
{
using (FileStream fs = new FileStream(@"C:\\RemoteDir\log.txt", FileMode.OpenOrCreate, FileAccess.Write, FileShare.Inheritable))
using(StreamWriter sw = new StreamWriter(fs))
{
sw.WriteLine("#" + message);
}
}
请记住,文件写入时会获得排他锁。 因此,如果两个线程同时写入,则其中一个将陷入异常。 阅读不是问题。 简单的解决方案是制作多个日志文件或使用数据库。 另一种方法是保持消息累积并在一个小时内或消息达到100条时写入一次。 制作字符串列表
List<string> messagelst= new List<string>();
private void WriteLog(string message)
{
messagelst.Add("New York");
messagelst.Add("Mumbai");
messagelst.Add("Berlin");
messagelst.Add("Istanbul");
if(messagelst.length==100){
string message= string.Join(",", messagelst.ToArray());
using (FileStream fs = new FileStream(@"C:\\RemoteDir\log.txt", FileMode.OpenOrCreate, FileAccess.Write, FileShare.Inheritable))
using(StreamWriter sw = new StreamWriter(fs))
{
sw.WriteLine("#" + message);
}
messagelst= new List<string>();
}
}
另一种方法是写异步。 您可能会松动顺序。
static Task ProcessWrite()
{
string filePath = @"c:\temp2\temp2.txt";
string text = "Hello World\r\n";
return WriteTextAsync(filePath, text);
}
static async Task WriteTextAsync(string filePath, string text)
{
byte[] encodedText = Encoding.Unicode.GetBytes(text);
using (FileStream sourceStream = new FileStream(filePath,
FileMode.Append, FileAccess.Write, FileShare.None,
bufferSize: 4096, useAsync: true))
{
await sourceStream.WriteAsync(encodedText, 0, encodedText.Length);
};
}
简短的答案: File.ReadAllLines
将不允许其他进程写入文件。 相关的SO问题有一些解决方法: File.ReadLines是否未锁定?
这一事实ReadAllLines
正在打开与该文件FileShare.Read
可以通过查看.NET参考的源代码中找到: https://referencesource.microsoft.com/#mscorlib/system/io/file.cs,5150c565446cd5fd
通过跟踪呼叫,最终将达到:
Stream stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, DefaultFileStreamBufferSize, FileOptions.SequentialScan, Path.GetFileName(path), false, false, checkHost);
FileShare.Read
说
允许随后打开文件进行读取。 如果未指定此标志,则打开文件以进行读取的任何请求(通过此过程或其他过程)都将失败,直到关闭文件为止。
即使ReadAllLines
将关闭文件,在读取过程中,该文件也不可供其他进程写入。
本质上,您需要使用FileShare.ReadWrite
(在进程A中)打开文件,以允许另一个进程(您的进程C)继续写入此文件。
您可以在写入文件时尝试将对象用作锁:
private static object fileLock = new Object();
现在在WriteLog
方法中:您可以使用lock(fileLock) {}
使用using来处理流。
您也可以看看EventWaitHandle 。 它允许为每个进程创建一个等待句柄的实例。
var wait = new EventWaitHandle(true, EventResetMode.AutoReset, "Common_to_all_process");
然后,在第一个进程完成后,可以通过发出信号将其传递到下一个进程:
wait.WaitOne();
/* write to the file*/
wait.Set();
可以将GUID用于“ Common_to_all_process”。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.