2012-08-06 41 views
0

我已經實現了一個基本的日誌記錄類,當我嘗試創建它的新實例時,我得到以下異常。爲什麼我會得到關於另一個進程正在使用的文件的IO異常?

該進程無法訪問文件'C:\ Users \ carl \ Desktop \ My Projects \ TCV2 \ CallPotential.UI \ bin \ Debug \ application.log',因爲它正在被另一個進程使用。

這裏是記錄器類的代碼。

using System; 
using System.IO; 
using System.Reflection; 

namespace CallPotential.Utilities 
{ 
    public class Logger : IDisposable 
    { 
     /// <summary> 
     /// Used to write output to the log file. 
     /// </summary> 
     private StreamWriter _stream; 

     /// <summary> 
     /// The absolute path to the log files location. 
     /// </summary> 
     public String LogFileName 
     { 
      get 
      { 
       // get the directory where our main assembly is located. 
       Assembly assembly = Assembly.GetExecutingAssembly(); 
       String directoryName = Path.GetDirectoryName(assembly.Location); 
       return Path.Combine(directoryName, "application.log"); 
      } 
     } 

     /// <summary> 
     /// Creates a new instance of the Logger class 
     /// </summary>   
     public Logger() 
     {   
      _stream = new StreamWriter(LogFileName);   
     } 

     /// <summary> 
     /// Writes a message out to the application log file. 
     /// </summary> 
     /// <param name="message">The message to write to the log file.</param> 
     public void Write(String message) 
     { 
      _stream.WriteLine(message); 
      _stream.Flush(); 
      _stream.Close(); 
     } 

     /// <summary> 
     /// Writes a message including the applications state to the log file. 
     /// </summary> 
     /// <param name="state">The application state at the time of the logged message.</param> 
     /// <param name="message">The message to be written to the log file.</param> 
     public void Write(AppState state, String message) 
     { 
      Write(String.Format("{0}\r\n\t{1}", state, message)); 
     } 

     public void Dispose() 
     { 
      Dispose(true); 
      GC.SuppressFinalize(this); 
     } 
     public void Dispose(bool disposing) 
     { 
      if (disposing) 
      { 
       if (_stream != null) 
       { 
        _stream.Dispose(); 
        _stream = null; 
       } 
      } 
     } 
     ~Logger() 
     { 
      Dispose(false); 
     } 
    } 
} 

注意確定爲什麼,但它會在構造函數中拋出異常。任何幫助搞清楚這一點將不勝感激。

+0

一種可能(我已經打了這一點)是寫入文件,並關閉它會觸發autovirus掃描儀,這將打開文件並阻止打開寫,當您登錄下一次。嘗試從病毒掃描中排除文件或目錄。 – 2012-08-06 21:20:47

+0

在我的開發機器上沒有安裝殺毒軟件,所以不能這樣做。我認爲myapplication.vhost對文件有鎖定,但我不確定。 – 2012-08-06 21:21:39

+0

在構造函數中,爲什麼你需要一個屬性來返回一個路徑?如果你總是希望文件與exe文件位於同一個目錄中,你可以使用新的StreamWriter(「application.log」);此外寫功能使用關閉,這是故意的,因爲你只能寫一次。你會希望close函數在dispose方法中。 – craig1231 2012-08-06 21:25:48

回答

1

當我嘗試創建它的新實例時,我得到以下異常。

您應該在創建新實例之前處置當前實例。

也許你應該考慮單身模式。

0

我總是用追加屬性的登錄狀態,這樣永遠不會忘記的流開

public void Write(AppState state, String message) 
    { 

     StreamWriter sw = new StreamWriter(LogFileName, true);// true to append the new text 
     sw.WriteLine(String.Format("{0}\r\n\t{1}", state, message)); 
     sw.Close(); // Close() is the same as Dispose() 
    } 
3

最根本的問題是,你拿着流開放的,這意味着你永遠只能訪問日誌記錄的一個實例除非你做了一些改變。

的各種變化,你可以使包括:

1)確保每個實例生成自己的日誌文件名。

2)強制所有日誌記錄記錄到在整個應用程序中使用的特定文件名。

在這兩種情況下,您都需要通過SyncLock塊來控制對關鍵功能的訪問,例如打開,關閉,讀取和寫入,以確保如果從線程登錄或使多個實例共享同一文件,一個調用者正在同時執行代碼。

在第一種情況下,您可能只想要一個實例。

在第二種情況下,您可以使用靜態的Streamwriter和靜態方法,因爲您不需要創建該類的新實例。這是我們多年前基於微軟在早期異常處理應用程序塊中提供的指導而實施的方法。

0

我能夠重現錯誤 - 例外是在第2行拋出:

var logger1 = new Logger(); 
var logger2 = new Logger(); 

但是當我使用Write()方法的第一個實例,那就是:

var logger1 = new Logger(); 
logger1.Write("XYZ"); 
var logger2 = new Logger(); 

這個例外不再被拋出。它在你的情況下表現如何?

問題是你對兩個記錄器使用相同的文件,如果你不關閉流或者處理第一個實例,你基本上試圖讓兩個流同時打開一個文件。

嘗試使用兩個不同的文件(例如,你可以傳遞路徑在構造函數中,而不必使用默認值屬性到日誌文件),並讓我知道這是否解決您的問題。

P.S.但是,如果你既需要記錄器寫入同一個文件,他們應該能夠在同一時間訪問該文件,那麼你應該採取不同的方法 - Singleton模式會比較合適。

0

你只能有你記錄的1個實例,永遠。但是,Visual Studio應用程序可能正在通過反射創建實例,因此它可以使用intellisense。 a)關閉主機進程,b)使用命令行編譯。

要解決您的具體問題,但是設計是壞的。

相關問題