2010-07-06 15 views
3

我有兩個C#應用程序,一個是逐行讀取文件(文件A)並將其內容寫入不同的文件(文件B)。爲什麼在嘗試從正在寫入的文件讀取時收到未處理的異常:System.IO.IOException?

第二個應用程序使用FileSystemWatcher for File B來查看它何時被更新,並報告不同之處是程序啓動時和文件更改時的行號。

這就是我現在要做的所有事情,最終我想讀取文件上次讀取和當前讀取之間的行,但直到我可以獲得保持的行差。

我對應用程序1的代碼是;

 static void Main(string[] args) 
    { 
     String line; 

     StreamReader sr = new StreamReader("f:\\watch\\input.txt"); 

     FileStream fs = new FileStream("f:\\watch\\Chat.log", FileMode.Create, FileAccess.Write, FileShare.ReadWrite); 
     StreamWriter sw = new StreamWriter(fs); 

     while ((line = sr.ReadLine()) != null) 
     { 
      sw.WriteLine(line); 
      Thread.Sleep(200); 
      Console.WriteLine(line); 
      sw.Flush(); 

     } 

     sw.Close(); 
     sr.Close(); 

    } 

我對應用程序2的代碼是;

 public static int lines = 0; 

    public static void Main() 
    { 
     Run(); 
    } 

    public static void Run() 
    { 
     string[] args = System.Environment.GetCommandLineArgs(); 

     if (args.Length != 2) 
     { 
      Console.WriteLine("Usage: Watcher.exe (directory)"); 
      return; 
     } 

FileSystemWatcher watcher = new FileSystemWatcher(); 
watcher.Path = args[1]; 

watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite 
    | NotifyFilters.FileName | NotifyFilters.DirectoryName; 

watcher.Filter = "Chat.log"; 

watcher.Changed += new FileSystemEventHandler(OnChanged); 

watcher.EnableRaisingEvents = true; 

lines = File.ReadAllLines(args[1] + "\\Chat.log").Length; 

Console.WriteLine("File lines: " + lines); 

while(Console.Read()!='q'); 
} 

private static void OnChanged(object source, FileSystemEventArgs e) 
{ 
    Linework(e.FullPath); 
    Console.WriteLine("File: " + e.FullPath + " " + e.ChangeType); 
} 

public static string Linework(string path) 

{ 



    string newstring = " "; 

using (FileStream stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) 
{ 
    int newlines = File.ReadAllLines(path).Length; 
    Console.WriteLine("Lines now: " + newlines); 
} 

return newstring; 

} 

現在,當我嘗試運行這兩個應用程序一起我得到一個異常說:「未處理的異常信息:System.IO.IOException:因爲它是由另一個進程使用該進程無法訪問文件」。

我有兩個文件流設置爲ReadWrite訪問,我有一個文件流設置FileAccess.Write和另一個FileAccess.Read。

任何線索,爲什麼我會得到這個異常?

謝謝 哎。

+0

哪個應用程序出錯? – spinon 2010-07-06 17:59:41

+0

FileShare.ReadWrite負責同時打開文件,但這是否也有助於同時訪問? – apoorv020 2010-07-06 18:06:44

+0

@ apoorv020:是的,即使是其他進程。但可能需要額外的權限。 – 2010-07-06 18:21:23

回答

7

線= File.ReadAllLines(參數[1] + 「\ Chat.log」)長度。

這是你的問題。該方法打開文件,讀取所有行並再次關閉它。它在打開文件FileShare.Read時使用「正常」文件共享設置。 拒絕寫入對任何其他同時打開該文件的進程的訪問權限。

這不能在這裏工作,你已經打開寫訪問文件。第二個過程不能否認它。 IOException是結果。

您不能像這裏一樣使用File.ReadAllLines(),您需要使用FileShare.ReadWrite打開FileStream,將它傳遞給StreamReader並讀取所有行。

請注意你在這裏遇到的非常麻煩的種族潛力,但不能保證你閱讀的最後一行是完整的一行。在行尾取得\ r而不是\ n是一個特別棘手的問題。這將會隨機且很少出現,這是最難解決的最難的錯誤。也許你的Flush()調用修復了它,我從來沒有足夠的勇氣來進行測試。

+0

+1令人印象深刻。我沿着這些線看到了一些東西,但無法用語言表達。 – 2010-07-06 20:00:47

+0

它已經寫在其他答案。至於讀數,你是對的。他可以使用一個有名的Mutex來輕鬆解決這個問題。 此外,他並沒有真正讀取這些行(如在其內容中),只是對它們進行計數。 – 2010-07-07 07:20:57

+0

謝謝漢斯,我嘗試使用Streamreader,但它確實工作,但我認爲讀取每一行來計算總行數比較將是低效的。因爲我一直在研究如何移除SafeFileHandles,所以我不打算選擇這個選項。 非常感謝。 – 2010-07-07 13:04:11

1

MSDN提供兩種方式無法獲得的獨家持有:

FileStream對象時不會被 訪問暴露手柄或 要麼SafeFileHandle擁有房產的手柄上的 獨家持有FileStream對象在其構造函數 中被賦予了 SafeFileHandle屬性。

的文檔意味着逆是真實的:

打開一個FileStream不設置SafeFileHandle意味着 的FileStream保持該文件句柄的專用保留(這是 內嵌的IO異常應該被拋出)。

+0

SafeHandle通常通過網絡套接字操作或文件映射暴露(在應用程序中不使用暴露文件句柄的代碼)。文件意味着什麼? – 2010-07-06 18:36:33

+0

它在引用中暗示。相反 當沒有訪問SafeFileHandle屬性以公開該句柄或FileStream對象在其構造函數中被賦予SafeFileHandle屬性時,fileStream對象將在其句柄上具有獨佔保持。 – 2010-07-06 18:52:11

+0

簡單句子演算: 句子:** FS將不具有專用保持** 句子B:** SafeFileHandle用於** 您使用'(B => A)'和'(〜。 B =>〜A)'不等於。 '(B => A)'和'(〜A =>〜B)'是等價的。 原始語句與以下內容相同:*如果使用SafeFileHandle,FS將不會有獨佔保留。* 所以等價的反轉含義是:*(SafeFileHandle是** NOT **使用) )* 這相當於:*(如果FS有獨佔保留),(SafeFileHandle是** NOT **使用)*。 這意味着您的答案中的句子不正確! – 2010-07-07 06:19:15

1
StreamReader sr = new StreamReader("f:\\watch\\input.txt"); 

input.txt中可能無法閱讀可用?

還在第一個應用程序中使用using而不是Close()(在拋出異常的情況下)。

否則就OK。文件共享可能需要額外的權限(但不能真正影響)。

我已經錯過了一段代碼:

int newlines = File.ReadAllLines(path).Length; 

使用streamStreamReader了點。

+0

感謝您使用「使用」的提示我改變了應用程序來做到這一點。權限應該沒問題,因爲我可以打開input.txt。我正在充分訪問系統。 – 2010-07-06 19:05:50

+0

對於'input.txt'我的意思是如果它沒有被另一個進程打開而沒有共享。 – 2010-07-06 19:23:32

4

允許第二個程序ReadWrite訪問該文件將在這種情況下工作。

//lines = File.ReadAllLines(args[1] + "\\Chat.log").Length; 
//Commenting the above lines as this would again open a new filestream on the chat.log 
//without the proper access mode required. 


    using (FileStream fsReader = new FileStream(args[1] + "\\Chat.log", FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite)) 
     { 
      using (StreamReader sr = new StreamReader(fsReader)) 
      { 
       while (sr.ReadLine() != null) 
        lines++; 
      } 
     } 
+0

+1正是OP所需要的。而不是'args [1] +「\\ Chat.log」'他會使用'path',因爲他已經在scope中定義了它。 – 2010-07-07 07:27:35

相關問題