为什么我得到另一个进程正在使用的文件的IO异常,而不是?

时间:2012-08-06 21:16:44

标签: c# .net winforms

我已经实现了一个基本的日志记录类,当我尝试创建它的新实例时,我得到以下异常。

该进程无法访问文件'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);
        }
    }
}

请注意确定原因,但它会在构造函数中抛出异常。任何帮助解决这个问题将不胜感激。

5 个答案:

答案 0 :(得分:3)

基本问题是您正在打开一个流,这意味着您只能访问一个日志记录类实例,除非您进行一些更改。

您可以进行各种更改:

1)确保每个实例都生成自己的日志文件名。

2)强制所有日志记录都记录到整个应用程序中使用的特定文件名。

在任何一种情况下,您都需要控制对关键功能的访问,例如打开,关闭,读取和写入SyncLock块,以确保如果您从线程记录或多个实例共享同一个文件,那么只有一个调用者正在同时执行代码。

在第一种情况下,您可能只想拥有一个实例。

在第二种情况下,您可以使用静态流写入器和静态方法,因为您不需要创建类的新实例。这是我们多年前根据Microsoft在早期异常处理应用程序块中的指导实现的方法。

答案 1 :(得分:1)

  

当我尝试创建它的新实例时,我得到以下异常。

您应该在创建新实例之前处置当前实例。

也许你应该考虑单身模式。

答案 2 :(得分:0)

我总是使用append属性进行日志记录,所以永远不要忘记流打开

    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 :(得分:0)

我能够重现错误 - 第二行引发了异常:

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

然而,当我在第一个实例上使用Write()方法时,即:

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

不再抛出异常了。在你的情况下它的行为方式是否相同?

问题是你对两个记录器使用相同的文件,如果你没有关闭流或处理第一个实例,你基本上试图让一个文件同时打开两个流。

尝试使用两个不同的文件(例如,您可以将路径传递给构造函数中的日志文件而不是具有默认值的属性)并告诉我这是否解决了您的问题。

P.S。但是,如果您需要两个记录器写入同一个文件并且它们应该能够同时访问该文件,那么您应该采取不同的方法 - 单例模式更合适。

答案 4 :(得分:0)

您只能拥有1个记录器实例。但是,visual studio应用程序可能正在通过反射创建一个实例,因此它可以使用intellisense。 a)关闭托管过程,b)使用命令行编译。

要解决您的具体问题,但设计很糟糕。