Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/276.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用StreamWriter实现滚动日志,并从顶部删除_C#_Winforms_Logging_File Io_Streamwriter - Fatal编程技术网

C# 使用StreamWriter实现滚动日志,并从顶部删除

C# 使用StreamWriter实现滚动日志,并从顶部删除,c#,winforms,logging,file-io,streamwriter,C#,Winforms,Logging,File Io,Streamwriter,我的C#winforms 4.0应用程序一直在使用线程安全的streamwriter来执行内部调试日志信息。当我的应用程序打开时,它会删除文件并重新创建它。当应用程序关闭时,它会保存文件 我想做的是修改我的应用程序,使其能够附加而不是替换。这是一个简单的解决方案 然而,我的问题是: 我想保持我的日志文件最大10兆左右。我的约束很简单。当您要关闭文件时,如果文件大于10兆字节,请删除前10% 是否有“更好”的方法,然后执行以下操作: 关闭文件 检查文件是否大于10兆欧 如果是,请打开该文件 分析整

我的C#winforms 4.0应用程序一直在使用线程安全的streamwriter来执行内部调试日志信息。当我的应用程序打开时,它会删除文件并重新创建它。当应用程序关闭时,它会保存文件

我想做的是修改我的应用程序,使其能够附加而不是替换。这是一个简单的解决方案

然而,我的问题是:

我想保持我的日志文件最大10兆左右。我的约束很简单。当您要关闭文件时,如果文件大于10兆字节,请删除前10%

是否有“更好”的方法,然后执行以下操作:

  • 关闭文件
  • 检查文件是否大于10兆欧
  • 如果是,请打开该文件
  • 分析整个事情
  • 剔除前10%
  • 把文件写回去
  • 接近
  • 编辑:好吧,我最终推出了我自己的(如下所示)建议公开迁移到Log4Net是一个很好的建议,但是学习新库和移动所有日志语句(数千条)所需的时间对于我试图进行的小改进来说并不及时

      private static void PerformFileTrim(string filename)
      {
         var FileSize = Convert.ToDecimal((new System.IO.FileInfo(filename)).Length);
    
         if (FileSize > 5000000)
         {
            var file = File.ReadAllLines(filename).ToList();
            var AmountToCull = (int)(file.Count * 0.33); 
            var trimmed = file.Skip(AmountToCull).ToList();
            File.WriteAllLines(filename, trimmed);
         }
      }
    

    我在浏览win32 api,我甚至不确定是否可以通过本机win32 vfs调用来实现这一点,更不用说通过.Net

    我唯一的解决方案是使用内存映射文件并手动移动数据,从.Net 4.0开始,.Net似乎支持这种方法


    我对此进行了一次研究,但从未提出任何建议,但我可以在这里为您提供方案B:

    我使用下面的选项最多保存3个日志文件。首先,创建日志文件1并将其附加到。当它超过maxsize时,将创建日志2和更高版本的日志3。当日志3太大时,将删除日志1,并将剩余的日志向下推送到堆栈中

    string[] logFileList = Directory.GetFiles(Path.GetTempPath(), "add_all_*.log", SearchOption.TopDirectoryOnly);
    if (logFileList.Count() > 1)
    {
        Array.Sort(logFileList, 0, logFileList.Count());
    }
    
    if (logFileList.Any())
    {
        string currFilePath = logFileList.Last();
        string[] dotSplit = currFilePath.Split('.');
        string lastChars = dotSplit[0].Substring(dotSplit[0].Length - 3);
        ctr = Int32.Parse(lastChars);
        FileInfo f = new FileInfo(currFilePath);
    
        if (f.Length > MaxLogSize)
        {
            if (logFileList.Count() > MaxLogCount)
            {
                File.Delete(logFileList[0]);
                for (int i = 1; i < MaxLogCount + 1; i++)
                {
                    Debug.WriteLine(string.Format("moving: {0} {1}", logFileList[i], logFileList[i - 1]));
                    File.Move(logFileList[i], logFileList[i - 1]); // push older log files back, in order to pop new log on top
                }
            }
            else
            {
                ctr++;
            }
        }
    }
    
    string[]logFileList=Directory.GetFiles(Path.GetTempPath(),“add_all.*.log”,SearchOption.TopDirectoryOnly);
    if(logFileList.Count()>1)
    {
    Sort(logFileList,0,logFileList.Count());
    }
    if(logFileList.Any())
    {
    字符串currFilePath=logFileList.Last();
    字符串[]dotSplit=currFilePath.Split('.');
    字符串lastChars=dotSplit[0]。子字符串(dotSplit[0]。长度-3);
    ctr=Int32.Parse(lastChars);
    FileInfo f=新的FileInfo(currFilePath);
    如果(f.Length>MaxLogSize)
    {
    if(logFileList.Count()>MaxLogCount)
    {
    File.Delete(logFileList[0]);
    对于(int i=1;i
    这是根据bigtech的回答得出的:

    private static string RollLogFile()
        {
            string path = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
            string appName = Path.GetFileNameWithoutExtension(Environment.GetCommandLineArgs()[0]);
            string wildLogName = string.Format("{0}*.log",appName);
    
            int fileCounter = 0;
            string[] logFileList = Directory.GetFiles(path, wildLogName, SearchOption.TopDirectoryOnly);
            if (logFileList.Length > 0)
            {
                Array.Sort(logFileList, 0, logFileList.Length);
                fileCounter = logFileList.Length - 1;
                //Make sure we apply the MaxLogCount (but only once to reduce the delay) 
                if (logFileList.Length > MaxLogCount)
                {
                    //Too many files - remove one and rename the others
                    File.Delete(logFileList[0]);
                    for (int i = 1; i < logFileList.Length; i++)
                    {
                        File.Move(logFileList[i], logFileList[i - 1]); 
                    }
                    --fileCounter;
                }
    
                string currFilePath = logFileList[fileCounter];
                FileInfo f = new FileInfo(currFilePath);
                if (f.Length < MaxLogSize)
                {
                    //still room in the current file
                    return currFilePath;
                }
                else
                {
                    //need another filename
                    ++fileCounter;                  
                }
    
            }
            return string.Format("{0}{1}{2}{3:00}.log", path, Path.DirectorySeparatorChar, appName, fileCounter);
        }
    

    这里的解决方案对我来说并不奏效。我接受了user3902302的答案,这也是基于bigtech的答案,并编写了一个完整的类。另外,我没有使用StreamWriter,您可以更改一行(针对StreamWrite AEEquivalent的AppendAllText)

    几乎没有错误处理(例如,当访问失败时重试访问,尽管锁应该捕获所有内部并发访问)

    对于一些以前不得不使用log4net或nlog等大型解决方案的人来说,这可能就足够了。(log4net RollingAppender甚至不是线程安全的,这一个是:)


    此功能将允许您根据工作日旋转日志。我们的应用程序第一次在星期一启动时,将检查星期一日期的任何现有条目,如果今天尚未初始化,将丢弃旧条目并重新初始化新文件。从那天起,该文件将继续将文本附加到同一日志文件中

    因此,总共将创建7个日志文件。 debug-Mon.txt,debog Tue.txt

    它还将添加实际记录消息的方法名以及日期和时间。非常适用于一般用途

    private void log(string text)
            {
                string dd = DateTime.Now.ToString("yyyy-MM-dd");
                string mm = DateTime.Now.ToString("ddd");
    
                if (File.Exists("debug-" + mm + ".txt"))
                {
                    String contents = File.ReadAllText("debug-" + mm + ".txt");
    
    
                    if (!contents.Contains("Date: " + dd))
                    {
                        File.Delete("debug-" + mm + ".txt");
                    }
                }
    
                File.AppendAllText("debug-" + mm + ".txt", "\r\nDate: " + DateTime.Now.ToString("yyyy-MM-dd HH:mm:s") + " =>\t" + new System.Diagnostics.StackFrame(1, true).GetMethod().Name + "\t" + text);
    
            }
    

    我喜欢greggorob64的解决方案,但也想压缩旧文件。除了将旧文件压缩为zip之外,它还提供了您所需的一切,您可以在此处找到:

    我将此作为应用程序初始化/重新初始化部分的一部分,因此它每天运行几次

    ErrorLogging.ManageLogs("Application.log");
    

    那么,如何使用为日志记录编写的、已经实现了此功能的特定库呢?(想起Log4Net)我还没有花时间研究Log4Net。到目前为止,我的simple streamwriter课程做得很好。如果Log4Net允许我寻找“滚动”日志,那么这绝对是我应该使用的解决方案。未来的读者:
    “…[移动]我所有的日志语句(数千条)不是有效的”
    -这就是我们依赖依赖依赖注入和接口的原因。:)更好的设计,比如注入
    ILogger
    (例如)所有需要日志记录的类的实例—甚至只有一个主日志记录类/函数—将允许您在日志记录要求更改时在一个位置修改所有日志记录功能。内存映射文件对于10mb文件来说是一个过多的问题我必须做一些修改才能让它为我运行—我将其作为一个单独的答案添加因为尺寸限制。。。
        private static void PerformFileTrim(string filename)
        {
            var fileSize = (new System.IO.FileInfo(filename)).Length;
    
            if (fileSize > 5000000)
            {
                var text = File.ReadAllText(filename);
                var amountToCull = (int)(text.Length * 0.33);
                amountToCull = text.IndexOf('\n', amountToCull);
                var trimmedText = text.Substring(amountToCull + 1);
                File.WriteAllText(filename, trimmedText);
            }
        }
    
    private void log(string text)
            {
                string dd = DateTime.Now.ToString("yyyy-MM-dd");
                string mm = DateTime.Now.ToString("ddd");
    
                if (File.Exists("debug-" + mm + ".txt"))
                {
                    String contents = File.ReadAllText("debug-" + mm + ".txt");
    
    
                    if (!contents.Contains("Date: " + dd))
                    {
                        File.Delete("debug-" + mm + ".txt");
                    }
                }
    
                File.AppendAllText("debug-" + mm + ".txt", "\r\nDate: " + DateTime.Now.ToString("yyyy-MM-dd HH:mm:s") + " =>\t" + new System.Diagnostics.StackFrame(1, true).GetMethod().Name + "\t" + text);
    
            }
    
    static int iMaxLogLength = 2000; // Probably should be bigger, say 200,000
    static int KeepLines = 5; // minimum of how much of the old log to leave
    
    public static void ManageLogs(string strFileName)
    {
        try
        {
            FileInfo fi = new FileInfo(strFileName);
            if (fi.Length > iMaxLogLength) // if the log file length is already too long
            {
                int TotalLines = 0;
                    var file = File.ReadAllLines(strFileName);
                    var LineArray = file.ToList();
                    var AmountToCull = (int)(LineArray.Count - KeepLines);
                    var trimmed = LineArray.Skip(AmountToCull).ToList();
                    File.WriteAllLines(strFileName, trimmed);
                    string archiveName = strFileName + "-" + DateTime.Now.ToString("MM-dd-yyyy") + ".zip";
                    File.WriteAllBytes(archiveName, Compression.Zip(string.Join("\n", file)));
            }
    
        }
        catch (Exception ex)
        {
            Console.WriteLine("Failed to write to logfile : " + ex.Message);
        }
    }
    
    ErrorLogging.ManageLogs("Application.log");