为什么我会收到有关文件正在被另一个进程使用的 IO 异常,而事实并非如此
本文关键字:进程 IO 异常 并非如此 事实 另一个 文件 为什么 | 更新日期: 2024-11-07 15:49:00
我已经实现了一个基本的日志记录类,当我尝试创建它的新实例时,我得到以下异常。
进程无法访问文件"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);
}
}
}
请注意确定原因,但它会在构造函数中引发异常。任何帮助解决这个问题将不胜感激。
基本问题是你保持流打开,这意味着你只能访问日志记录类的一个实例,除非你做了一些更改。
您可以进行的各种更改包括:
1) 确保每个实例都生成自己的日志文件名。
2) 强制所有日志记录记录到在整个应用程序中使用的特定文件名。
无论哪种情况,您都需要控制对关键功能的访问,例如通过 SyncLock 块打开、关闭、读取和写入,以确保如果从线程进行日志记录或有多个实例共享同一文件,则只有一个调用方同时执行代码。
在第一种情况下,您可能只想拥有一个实例。
在第二种情况下,您可以使用静态流编写器和静态方法,因为您不需要创建类的新实例。这是我们多年前根据早期异常处理应用程序块中Microsoft的指导实现的方法。
当我尝试创建它的新实例时,出现以下异常。
您应该在创建新实例之前释放当前实例。
也许您应该考虑单例模式。
我总是使用 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()
}
我能够重现错误 - 第二行抛出异常:
var logger1 = new Logger();
var logger2 = new Logger();
但是当我在第一个实例上使用 Write() 方法时,即:
var logger1 = new Logger();
logger1.Write("XYZ");
var logger2 = new Logger();
异常不再被抛出。它的行为方式是否与您相同?
问题是您对两个记录器使用相同的文件,如果您不关闭流或释放第一个实例,您基本上是在尝试同时为一个文件打开两个流。
尝试使用两个不同的文件(例如,您可以在构造函数中传递日志文件的路径,而不是具有默认值的属性),并让我知道这是否解决了您的问题。
附言但是,如果您需要两个记录器写入同一个文件,并且它们应该能够同时访问该文件,那么您应该采取不同的方法 - 单例模式会更合适。
永远只能有 1 个记录器实例。 但是,Visual Studio 应用程序可能通过反射创建实例,因此它可以使用智能感知。 a) 关闭托管进程,b) 使用命令行编译。
解决您的特定问题,但是设计很糟糕。