这让我坚持不懈,所以如果有人能够,我会非常感激!!
我正在尝试将我的信息记录到日志文件中,因此我使用了Logger类。
** Logger.cs **
public class Logger : IDisposable
{
private readonly FileStream _file; //Only this instance have a right to own it
private readonly StreamWriter _writer;
private readonly object _mutex; //Mutex for synchronizing
/// <summary>
/// Call this function to use the text file
/// </summary>
/// <param name="logPath"></param>
public Logger(string logPath)
{
if (logPath != null) _file = new FileStream(logPath, FileMode.Append);
_writer = new StreamWriter(_file);
_mutex = new object();
}
// Log is thread safe, it can be called from many threads
public void Log(string message)
{
lock (_mutex)
{
//_writer.Write("\r\nLog Entry : ");
// _writer.WriteLine("{0} {1}", DateTime.Now.ToLongTimeString(),
//DateTime.Now.ToLongDateString());
_writer.WriteLine("{0} {1}", DateTime.Now.ToString("yyyy-MM-dd"),
DateTime.Now.ToLongTimeString());
_writer.WriteLine(message);
}
}
/// <summary>
/// Call this function when it says file is already been using somewhere
/// </summary>
public void Dispose()
{
_writer.Dispose(); //Will close underlying stream
}
}
**我的应用程序使用记录器类**
private void button1_Click(object sender, EventArgs e)
{
// This is the file path after d://dashboardLogfiles
String filePath = string.Format("{0:yyyy-MM-dd}", DateTime.Now);
// This is the text file created with time stamps
String txtFile = string.Format("DataSummarisation{0:yyyy-MM-dd hh-mm-ss-tt}", DateTime.Now);
// Given in config to read the path
var localhostizedLetter = @"d:/";
//Create directory
string pathString = Path.Combine(localhostizedLetter, "DataSummarisationLogfiles");
if (!Directory.Exists(pathString))
{
Directory.CreateDirectory(pathString);
}
// Create a folder inside directory
// If folder exists dont create it
pathString = Path.Combine(pathString, filePath);
if (!Directory.Exists(pathString))
{
Directory.CreateDirectory(pathString);
}
// create a file inside d://DataSummarisationDatetime.now//datetimewithtimestamp.txt
// if exists please dont create it.
pathString = Path.Combine(pathString, txtFile);
if (!Directory.Exists(pathString))
{
// here my file is created and opened.
// so I m doing a try catch to make sure if file is opened we are closing it so that nother process can use it
File.Create(pathString).Dispose();
var fileInfo = new FileInfo(pathString);
// IsFileLocked(fileInfo);
}
_logger = new Logger(pathString);
_logger.Log("Log File Created");
_logger.Dispose();
ThreadStart starter = () => MigrateProductStats(123, 0, pathString);
var thread = new Thread(starter);
thread.Start();
}
**我的函数使用相同的记录器路径**
private void MigrateProductStats(object corporationIdObj, object brandIdObj, object logFilePath)
{
_logger = new Logger(logFilePath.ToString());
_logger.Log("Am I still writing to same file?");
_logger.Dispose();
for (int i = 0; i <= 10;i++ )
{
DoProductStatsForCorporation(123, logFilePath.ToString());
}
}
private void DoProductStatsForCorporation(int corporationId, string logFilePath)
{
_logger = new Logger(logFilePath);
_logger.Log("Am I still writing to same file second time?");
_logger.Dispose();
}
**以上情景正在运作**
**但是我希望传递对象而不是Path以避免重新实现**
ThreadStart starter = () => MigrateProductStats(123, 0, _logger);
var thread = new Thread(starter);
thread.Start();
在上面的情况下,在我的按钮单击我处理记录器并发送路径到函数DoProductStatsForCorporation和MigrateProductStats而不是如果我尝试发送_logger对象而不处理它并避免重新加入我的子函数我收到错误不能写入文件,因为它被另一个进程使用。
我希望这是有道理的!
任何有关这方面的指导都会非常感激,因为我非常关注这个问题。
答案 0 :(得分:2)
你遇到的问题是它是MT,很可能你可能正在写一个已经打开的文件(竞争条件)
为什么不为记录器/编写器使用单例?为什么不锁定编写器并且只使用一个实例而不是总是创建一个新实例?
你的路径字符串看起来也很错误。我的意思是为什么要在文件名中吐出最后一个毫秒/刻度?
我建议您使用单例方法进行日志记录,或者如果必须,创建记录器的静态实例并在编写时锁定文件,并在完成时进行处置。您正在写入可能正在使用的文件,而其他线程正在访问该文件。确保文件名也是唯一的 - 它可能看起来不像你认为的那样。
答案 1 :(得分:2)
static
然后同步这样的方法:
[MethodImpl(MethodImplOptions.Synchronized)]
public static void Log(string description)
然后,使用并处理内联编写器以避免这些问题。
using (var writer = new StreamWriter(Path + "\\" + LOG_FILE, true))
{
writer.WriteLine(log);
writer.Close();
}
答案 2 :(得分:1)
对于初学者DoProductStatsForCorporation
,记录器不应该是此功能的参数。
您的记录器应该在开始时创建,并在课堂上创建一个字段。
您不希望将记录器传递给函数,因为函数实际上并不需要此记录器来完成其工作。
将记录器移出某些按钮代码,在构造函数中创建它,并使用类似于发生日志记录的类中的私有字段。
如果要更改同一类中的日志文件并登录到不同的文件,则必须重写logger类,以便它可以使用多个文件。
你也可以了解Log4net,这真的很不错。