繁体   English   中英

共享网络文件以进行读写

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM