如何在C#中编写日志文件?

71

我该如何在C#中编写日志文件?

目前,我有一个计时器,每20秒会触发以下语句:

File.WriteAllText(filePath+"log.txt", log);

对于我想要记录的所有内容,我都会这样做:

log += "stringToBeLogged";

你可以想象字符串日志随着程序的运行而不断增长。(我甚至不知道一个字符串有没有最大字符限制?)

我认为一定有更好的方法来做这件事。我只是觉得每次向日志添加内容时都完整地重新写入整个文件会很费力。


7
我建议发现与log4net类似的东西。 - cnd
12个回答

77

从性能角度来看,你的解决方案并不是最优的。每次使用 += 添加另一个日志条目时,整个字符串都会复制到内存中的另一个位置。我建议改用 StringBuilder :

StringBuilder sb = new StringBuilder();
...
sb.Append("log something");

...
// flush every 20 seconds as you do it
File.AppendAllText(filePath+"log.txt", sb.ToString());
sb.Clear();

顺便提一下,您的计时器事件可能在另一个线程上执行。因此,在访问sb对象时,您可能需要使用互斥锁。

还有一件事要考虑,就是最后20秒内添加的日志条目会发生什么情况。您可能希望在应用程序退出前将字符串刷新到文件中。


2
这里和这里是另一个解决方案。希望能有所帮助。 - Shaiju T
1
如果文件被多个进程并行使用,它将抛出异常。此外,它不是线程安全的。 - Hiren Patel
1
这似乎只能运行一次。如果再次运行程序,它将不会追加或覆盖文件。 - user736893

71

创建一个类,创建一个全局对象并调用它

using System.IO;
using System.Reflection;


   public class LogWriter
{
    private string m_exePath = string.Empty;
    public LogWriter(string logMessage)
    {
        LogWrite(logMessage);
    }
    public void LogWrite(string logMessage)
    {
        m_exePath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
        try
        {
            using (StreamWriter w = File.AppendText(m_exePath + "\\" + "log.txt"))
            {
                Log(logMessage, w);
            }
        }
        catch (Exception ex)
        {
        }
    }

    public void Log(string logMessage, TextWriter txtWriter)
    {
        try
        {
            txtWriter.Write("\r\nLog Entry : ");
            txtWriter.WriteLine("{0} {1}", DateTime.Now.ToLongTimeString(),
                DateTime.Now.ToLongDateString());
            txtWriter.WriteLine("  :");
            txtWriter.WriteLine("  :{0}", logMessage);
            txtWriter.WriteLine("-------------------------------");
        }
        catch (Exception ex)
        {
        }
    }
}

2
这是一个非常棒的解决方案,运行得非常优雅! - Merin Nakarmi
2
很好,但如果使用静态类和方法,代码会更加简洁。 - Loïc Sombart
1
就像魔法一样轻松。直接复制粘贴就可以了。 - Siva Makani
1
太棒了!只需删除构造函数(public LogWriter ...)部分并将静态关键字添加到类描述(public static void LogWrite)中,就可以简单地将其更改为.NET 6的静态类。然后,该类变成全局可用,无需每次记录日志时构建它。 - Thumper33
1
你应该如何调用这个函数?是 LogWriter.LogWrite("test") 吗? - user736893
显示剩余2条评论

25

3
只是一个小提示:确保你的文件路径以斜杠结尾或者添加一个。你还应该添加一行新代码,类似于 File.AppendAllText(filePath + "\" + "log.txt", log + Environment.NewLine); - nixda
鉴于问题中指定了log += "stringToBeLogged";,这样做不会正常工作,因为会增量添加相同的信息。应该使用类似于File.AppendAllText(filePath + "log.txt", 'stringToBeLogged');的东西。 - Alex P.
@AlexPandrea 对,如果他每次都记录相同的“log”,那么使用File.WriteAllText会更好,尽管这有点过度。该解决方案建议每次仅记录特定信息(追加),而不是写入完整的“log”变量。 - matth
2
@nixda,最好使用Path.DirectorySeparatorChar而不是硬编码的\ char - Artfaith
2
@Angel,可以使用Path.Combine方法代替Path.DirectorySeparatorChar。例如:Path.Combine(filePath, "log.txt") - polfosol ఠ_ఠ
如果文件被多个进程并行使用,它将抛出异常。此外,它不是线程安全的。 - Hiren Patel

17
public static void WriteLog(string strLog)
    {
        StreamWriter log;
        FileStream fileStream = null;
        DirectoryInfo logDirInfo = null;
        FileInfo logFileInfo;

        string logFilePath = "C:\\Logs\\";
        logFilePath = logFilePath + "Log-" + System.DateTime.Today.ToString("MM-dd-yyyy") + "." + "txt";           
        logFileInfo = new FileInfo(logFilePath);
        logDirInfo = new DirectoryInfo(logFileInfo.DirectoryName);
        if (!logDirInfo.Exists) logDirInfo.Create();
        if (!logFileInfo.Exists)
        {
            fileStream = logFileInfo.Create();
        }
        else
        {
            fileStream = new FileStream(logFilePath, FileMode.Append);
        }
        log = new StreamWriter(fileStream);
        log.WriteLine(strLog);
        log.Close();
    }   

Refer Link: blogspot.in


6
使用嵌套的 using() 块、StreamWriterFileStream 可能是个不错的主意。 - RhinoDevel

11

如@randymohan所发布的,使用语句替代

public static void WriteLog(string strLog)
{
    string logFilePath = @"C:\Logs\Log-" + System.DateTime.Today.ToString("MM-dd-yyyy") + "." + "txt";
    FileInfo logFileInfo = new FileInfo(logFilePath);
    DirectoryInfo logDirInfo = new DirectoryInfo(logFileInfo.DirectoryName);
    if (!logDirInfo.Exists) logDirInfo.Create();
    using (FileStream fileStream = new FileStream(logFilePath, FileMode.Append))
    {
        using (StreamWriter log = new StreamWriter(fileStream))
        {
            log.WriteLine(strLog);
        }
    }
}

1
在执行 new FileStream 之前不要创建文件,它会自动创建文件。 - A.Pissicat
1
删除了文件存在检查。 - moldypenguins

7

使用静态类将日志添加到文件中

 public static class LogWriter
        {
            private static string m_exePath = string.Empty;
            public static void LogWrite(string logMessage)
            {
                m_exePath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
                if (!File.Exists(m_exePath + "\\" + "log.txt"))
                    File.Create(m_exePath + "\\" + "log.txt");

                try
                {
                    using (StreamWriter w = File.AppendText(m_exePath + "\\" + "log.txt"))
                        AppendLog(logMessage, w);
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                }

            }

            private static void AppendLog(string logMessage, TextWriter txtWriter)
            {
                try
                {
                    txtWriter.Write("\r\nLog Entry : ");
                    txtWriter.WriteLine("{0} {1}", DateTime.Now.ToLongTimeString(),DateTime.Now.ToLongDateString());
                    txtWriter.WriteLine("  :");
                    txtWriter.WriteLine("  :{0}", logMessage);
                    txtWriter.WriteLine("-------------------------------");
                }
                catch (Exception ex)
                {
                }
            }
        }

这个类需要稍微修改一下: m_exePath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); if (!File.Exists(m_exePath + "\" + "log.txt")){ string s = ""; s = DateTime.Now.ToString("h:mm:ss tt"); FileStream fs = File.Create(m_exePath + "\" + "log.txt"); Byte[] info = new UTF8Encoding(true).GetBytes("文件已创建:"+s+"\r\n"); fs.Write(info, 0, info.Length); fs.Close(); }否则,在第一次程序启动时,你会遇到异常。 - Jevgenij Kononov
仅创建文件后立即关闭,或者简单地关闭文件。 - Jevgenij Kononov

7

2
有很多关于Log4net的好教程。这个是我开始学习Log4net的地方:http://www.codeproject.com/Articles/140911/log4net-Tutorial - Jastill

4
if(!File.Exists(filename)) //No File? Create
{
    fs = File.Create(filename);
    fs.Close();
}
if(File.ReadAllBytes().Length >= 100*1024*1024) // (100mB) File to big? Create new
{
    string filenamebase = "myLogFile"; //Insert the base form of the log file, the same as the 1st filename without .log at the end
    if(filename.contains("-")) //Check if older log contained -x
    {
         int lognumber = Int32.Parse(filename.substring(filename.lastIndexOf("-")+1, filename.Length-4); //Get old number, Can cause exception if the last digits aren't numbers
         lognumber++; //Increment lognumber by 1
         filename = filenamebase + "-" + lognumber + ".log"; //Override filename
    }
    else 
    {
         filename = filenamebase + "-1.log"; //Override filename
    }
    fs = File.Create(filename);
    fs.Close();
}

参考链接:

http://www.codeproject.com/Questions/163337/How-to-write-in-log-Files-in-C

这篇文章介绍了在 C 语言中如何编写日志文件。

2

这是在文件中添加新字符串

using (var file = new StreamWriter(filePath + "log.txt", true))
        {
            file.WriteLine(log);
            file.Close();
        }

1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接