簡體   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