【问题标题】:Mirroring console output to a file将控制台输出镜像到文件
【发布时间】:2010-09-30 01:03:16
【问题描述】:

在 C# 控制台应用程序中,是否有一种巧妙的方法可以将控制台输出镜像到文本文件?

目前我只是在日志方法中将相同的字符串传递给Console.WriteLineInstanceOfStreamWriter.WriteLine

【问题讨论】:

    标签: c# .net file text console


    【解决方案1】:

    这可能需要更多的工作,但我会反过来。

    为控制台实例化一个TraceListener,为日志文件实例化一个;此后在您的代码中使用Trace.Write 语句而不是Console.Write。之后删除日志、控制台输出或附加其他日志记录机制变得更容易。

    static void Main(string[] args)
    {
        Trace.Listeners.Clear();
    
        TextWriterTraceListener twtl = new TextWriterTraceListener(Path.Combine(Path.GetTempPath(), AppDomain.CurrentDomain.FriendlyName));
        twtl.Name = "TextLogger";
        twtl.TraceOutputOptions = TraceOptions.ThreadId | TraceOptions.DateTime;
    
        ConsoleTraceListener ctl = new ConsoleTraceListener(false);
        ctl.TraceOutputOptions = TraceOptions.DateTime;
    
        Trace.Listeners.Add(twtl);
        Trace.Listeners.Add(ctl);
        Trace.AutoFlush = true;
    
        Trace.WriteLine("The first line to be in the logfile and on the console.");
    }
    

    据我所知,您可以在应用程序配置中定义侦听器,从而可以在不接触构建的情况下激活或停用日志记录。

    【讨论】:

    • 太完美了——谢谢。我知道 Log4Net,但为了这样的事情必须引入一个库似乎是错误的。
    • 我不知道他们为什么不做更多的 Trace——在我看来它应该适用于生产规模的日志记录,但每个人都想增加一个额外的库(如 log4net)来做到这一点。
    • 这是一种单向镜像。我的意思是,如果您有一个交互式控制台并从用户那里获取一些数据并希望将所有内容记录在一个文件中,则此解决方案不起作用。尽管有这个简单的事实,但我的问题已经结束。这里:stackoverflow.com/questions/3886895/…
    • 我真的很喜欢这个解决方案,所以我写了一篇关于它的快速博客,并在此过程中进行了一些小的清理和一些障碍的演练。 mcrook.com/2014/11/quick-and-easy-console-logging-trace.html感谢您的出色解决方案:)
    【解决方案2】:

    这是一个简单的类,它继承了 TextWriter 以允许将输入重定向到文件和控制台。

    这样使用

      using (var cc = new ConsoleCopy("mylogfile.txt"))
      {
        Console.WriteLine("testing 1-2-3");
        Console.WriteLine("testing 4-5-6");
        Console.ReadKey();
      }
    

    这是课程:

    class ConsoleCopy : IDisposable
    {
    
      FileStream fileStream;
      StreamWriter fileWriter;
      TextWriter doubleWriter;
      TextWriter oldOut;
    
      class DoubleWriter : TextWriter
      {
    
        TextWriter one;
        TextWriter two;
    
        public DoubleWriter(TextWriter one, TextWriter two)
        {
          this.one = one;
          this.two = two;
        }
    
        public override Encoding Encoding
        {
          get { return one.Encoding; }
        }
    
        public override void Flush()
        {
          one.Flush();
          two.Flush();
        }
    
        public override void Write(char value)
        {
          one.Write(value);
          two.Write(value);
        }
    
      }
    
      public ConsoleCopy(string path)
      {
        oldOut = Console.Out;
    
        try
        {
          fileStream = File.Create(path);
    
          fileWriter = new StreamWriter(fileStream);
          fileWriter.AutoFlush = true;
    
          doubleWriter = new DoubleWriter(fileWriter, oldOut);
        }
        catch (Exception e)
        {
          Console.WriteLine("Cannot open file for writing");
          Console.WriteLine(e.Message);
          return;
        }
        Console.SetOut(doubleWriter);
      }
    
      public void Dispose()
      {
        Console.SetOut(oldOut);
        if (fileWriter != null)
        {
          fileWriter.Flush();
          fileWriter.Close();
          fileWriter = null;
        }
        if (fileStream != null)
        {
          fileStream.Close();
          fileStream = null;
        }
      }
    
    }
    

    【讨论】:

    • 我认为这是最完整的解决方案。无需重写 Write/WriteLine 方法的所有重载,并且对其他代码是透明的。因此,所有控制台活动都将复制到文件中,而无需对其他代码进行任何更改。
    • 谢谢你!这很棒!我刚刚将 File.Create 替换为 File.Open(path, FileMode.Append, FileAccess.Write, FileShare.Read); 因为我不想删除旧日志启动,我希望能够在程序仍在运行时打开日志文件。
    • 这不需要我替换所有对 Console.WriteLine() 的现有调用,这正是我想要的。
    • 对于那些摇摆不定的人来说,这是如何做到的。寻找Console.SetOut(doubleWriter);。这是修改控制台的全局,我花了一点时间,因为我已经习惯于在几乎没有全局的应用程序中工作。好东西!
    • 我喜欢这个,但由于某种原因,它会大大减慢我的应用程序,因为它将进度记录到控制台。奇怪的是,即使我注释掉 one.Flush()one.Write(value) 以将文件 IO 排除在等式之外,它仍然会减慢速度。
    【解决方案3】:

    查看log4net。使用 log4net,您可以设置控制台和文件附加程序,它们可以使用单个日志语句将日志消息输出到两个位置。

    【讨论】:

    • 好吧,我认为应该避免额外的库,如果可以使用已经存在的库。
    • 我也推荐 log4net,但看起来 NLog 正在社区中占据一席之地。
    【解决方案4】:

    您不能使用> 命令将输出重定向到文件吗?

    c:\>Console.exe > c:/temp/output.txt
    

    如果需要镜像,可以尝试查找tee的win32版本,将输出拆分为文件。

    请参阅https://superuser.com/questions/74127/tee-for-windows 以从 PowerShell 运行 tee

    【讨论】:

    • 我确实需要镜像。这就是为什么在主题和正文中提到它的原因。不过感谢您的提示:)
    【解决方案5】:

    您可以子类化 TextWriter 类,然后使用 Console.SetOut 方法将其实例分配给 Console.Out - 这与将相同字符串传递给 log 方法中的两个方法的作用相同。

    另一种方式可能是声明您自己的 Console 类并使用 using 语句来区分这些类:

    using Console = My.Very.Own.Little.Console;
    

    要访问您需要的标准控制台:

    global::Console.Whatever
    

    【讨论】:

      【解决方案6】:

      编辑:此方法提供了重定向来自第三方包的控制台信息的可能性。重写 WriteLine 方法对我的情况很好,但是您可能需要重写其他 Write 方法取决于第三方包。

      首先我们需要创建 StreamWriter 固有的新类,比如 CombinedWriter;

      然后用 Console.Out 初始化一个新的 CombinedWriter;

      最后我们可以通过 Console.SetOut 将控制台输出重定向到新类的时刻;

      以下代码是适合我的新类。

      public class CombinedWriter : StreamWriter
      {
          TextWriter console;
          public CombinedWriter(string path, bool append, Encoding encoding, int bufferSize, TextWriter console)
              :base(path, append, encoding, bufferSize)
          {
              this.console = console;
              base.AutoFlush = true; // thanks for @konoplinovich reminding
          }
          public override void WriteLine(string value)
          {
              console.Write(value);
              base.WriteLine(value);
          }
      }
      

      【讨论】:

      • 这样我们就不会错过控制台中显示的任何内容。
      • 您应该覆盖以下方法public override void Write(char value);public override void Write(char[] buffer);public override void Write(string value);public override void Write(char[] buffer, int index, int count);。否则,如果您使用 WriteLine(format, ...) 方法,它不会打印到控制台。
      【解决方案7】:

      Log4net 可以为您做到这一点。你只会写这样的东西:

      logger.info("Message");
      

      配置将决定打印输出是转到控制台、文件还是两者。

      【讨论】:

        【解决方案8】:

        我认为您已经使用的是最好的方法。一种从本质上反映您的输出的简单方法。

        首先在开头声明一个全局TextWriter:

        private TextWriter txtMirror = new StreamWriter("mirror.txt");
        

        然后制作一个写法:

        // Write empty line
        private void Log()
        {
            Console.WriteLine();
            txtMirror.WriteLine();
        }
        
        // Write text
        private void Log(string strText)
        {
            Console.WriteLine(strText);
            txtMirror.WriteLine(strText);
        }
        

        现在,不要使用Console.WriteLine("...");,而是使用Log("...");。就那么简单。它甚至更短!


        如果你移动光标位置(Console.SetCursorPosition(x, y);)可能会有些麻烦,但其他效果很好,我自己也用它!

        编辑

        当然,如果你不只使用 WriteLines,你也可以用同样的方式为 Console.Write(); 创建一个方法

        【讨论】:

        • 这是最简单的解决方案。不要忘记在程序末尾添加:
          txtMirror.Flush(); txtMirror.Close();
        【解决方案9】:

        正如 Arul 所建议的,使用 Console.SetOut 可用于将输出重定向到文本文件:

        Console.SetOut(new StreamWriter("Output.txt"));
        

        【讨论】:

          【解决方案10】:

          使用继承自 StreamWriter 的类的决定以及用户 Keep Thinking 的建议是有效的。 但我必须添加到构造函数 base.AutoFlush = true:

          {
              this.console = console;
              base.AutoFlush = true;
          }
          

          以及对析构函数的显式调用:

          public new void Dispose ()
          {
              base.Dispose ();
          }
          

          否则,文件在他记录所有数据之前就被关闭了。

          我将它用作:

          CombinedWriter cw = new CombinedWriter ( "out.txt", true, Encoding.Unicode, 512, Console.Out );
          Console.SetOut (cw);
          

          【讨论】:

            【解决方案11】:

            感谢 Keep Thinking 提供出色的解决方案!我添加了一些进一步的覆盖以避免记录某些控制台写入事件(出于我的目的),这些事件仅用于控制台显示。

            using System;
            using System.IO;
            using System.Collections.Generic;
            using System.Linq;
            using System.Text;
            
            namespace RedirectOutput
            {
                public class CombinedWriter  : StreamWriter
                {
                    TextWriter console;
                    public CombinedWriter(string path, bool append, TextWriter consoleout)
                        : base(path, append)
                    {
                        this.console = consoleout;
                        base.AutoFlush = true;
                    }
                    public override void Write(string value)
                    {
                        console.Write(value);
                        //base.Write(value);//do not log writes without line ends as these are only for console display
                    }
                    public override void WriteLine()
                    {
                        console.WriteLine();
                        //base.WriteLine();//do not log empty writes as these are only for advancing console display
                    }
                    public override void WriteLine(string value)
                    {
                        console.WriteLine(value);
                        if (value != "")
                        {
                            base.WriteLine(value);
                        }
                    }
                    public new void Dispose()
                    {
                        base.Dispose();
                    }
                }
                class Program
                {
                    static void Main(string[] args)
                    {
                        CombinedWriter cw = new CombinedWriter("combined.log", false, Console.Out);
                        Console.SetOut(cw);
                        Console.WriteLine("Line 1");
                        Console.WriteLine();
                        Console.WriteLine("Line 2");
                        Console.WriteLine("");
                        for (int i = 0; i < 10; i++)
                        {
                            Console.Write("Waiting " + i.ToString());
                            Console.CursorLeft = 0;
                        }
                        Console.WriteLine();
                        for (int i = 0; i < 10; i++)
                        {
                            Console.Write("Waiting " + i.ToString());
                        }
                        Console.WriteLine();
                        Console.WriteLine("Line 3");
                        cw.Dispose();
                    }
                }
            }
            

            【讨论】:

            • 您替换 Dispose 方法然后调用 base.Dispose() 的任何特殊原因?
            【解决方案12】:

            如果您从您无法控制的代码(例如 3rd 方库)复制控制台输出,则应覆盖 TextWriter 的所有成员。代码使用了这个线程的想法。

            用法:

            using (StreamWriter writer = new StreamWriter(filePath))
            {
               using (new ConsoleMirroring(writer))
               {
                   // code using console output
               }
            }
            

            ConsoleMirroring 类

            public class ConsoleMirroring : TextWriter
            {
                private TextWriter _consoleOutput;
                private TextWriter _consoleError;
            
                private StreamWriter _streamWriter;
            
                public ConsoleMirroring(StreamWriter streamWriter)
                {
                    this._streamWriter = streamWriter;
                    _consoleOutput = Console.Out;
                    _consoleError = Console.Error;
            
                    Console.SetOut(this);
                    Console.SetError(this);
                }
            
                public override Encoding Encoding { get { return _consoleOutput.Encoding; } }
                public override IFormatProvider FormatProvider { get { return _consoleOutput.FormatProvider; } }
                public override string NewLine { get { return _consoleOutput.NewLine; } set { _consoleOutput.NewLine = value; } }
            
                public override void Close()
                {
                    _consoleOutput.Close();
                    _streamWriter.Close();
                }
            
                public override void Flush()
                {
                    _consoleOutput.Flush();
                    _streamWriter.Flush();
                }
            
                public override void Write(double value)
                {
                    _consoleOutput.Write(value);
                    _streamWriter.Write(value);
            
                }
                public override void Write(string value)
                {
                    _consoleOutput.Write(value);
                    _streamWriter.Write(value);
            
                }
            
                public override void Write(object value)
                {
                    _consoleOutput.Write(value);
                    _streamWriter.Write(value);
            
                }
            
                public override void Write(decimal value)
                {
                    _consoleOutput.Write(value);
                    _streamWriter.Write(value);
            
                }
            
                public override void Write(float value)
                {
                    _consoleOutput.Write(value);
                    _streamWriter.Write(value);
            
                }
            
                public override void Write(bool value)
                {
                    _consoleOutput.Write(value);
                    _streamWriter.Write(value);
            
                }
            
                public override void Write(int value)
                {
                    _consoleOutput.Write(value);
                    _streamWriter.Write(value);
            
                }
            
                public override void Write(uint value)
                {
                    _consoleOutput.Write(value);
                    _streamWriter.Write(value);
            
                }
            
                public override void Write(ulong value)
                {
                    _consoleOutput.Write(value);
                    _streamWriter.Write(value);
            
                }
            
                public override void Write(long value)
                {
                    _consoleOutput.Write(value);
                    _streamWriter.Write(value);
            
                }
            
                public override void Write(char[] buffer)
                {
                    _consoleOutput.Write(buffer);
                    _streamWriter.Write(buffer);
            
                }
            
                public override void Write(char value)
                {
                    _consoleOutput.Write(value);
                    _streamWriter.Write(value);
            
                }
            
                public override void Write(string format, params object[] arg)
                {
                    _consoleOutput.Write(format, arg);
                    _streamWriter.Write(format, arg);
            
                }
            
                public override void Write(string format, object arg0)
                {
                    _consoleOutput.Write(format, arg0);
                    _streamWriter.Write(format, arg0);
            
                }
            
                public override void Write(string format, object arg0, object arg1)
                {
                    _consoleOutput.Write(format, arg0, arg1);
                    _streamWriter.Write(format, arg0, arg1);
            
                }
            
                public override void Write(char[] buffer, int index, int count)
                {
                    _consoleOutput.Write(buffer, index, count);
                    _streamWriter.Write(buffer, index, count);
            
                }
            
                public override void Write(string format, object arg0, object arg1, object arg2)
                {
                    _consoleOutput.Write(format, arg0, arg1, arg2);
                    _streamWriter.Write(format, arg0, arg1, arg2);
            
                }
            
                public override void WriteLine()
                {
                    _consoleOutput.WriteLine();
                    _streamWriter.WriteLine();
            
                }
            
                public override void WriteLine(double value)
                {
                    _consoleOutput.WriteLine(value);
                    _streamWriter.WriteLine(value);
            
                }
                public override void WriteLine(decimal value)
                {
                    _consoleOutput.WriteLine(value);
                    _streamWriter.WriteLine(value);
            
                }
                public override void WriteLine(string value)
                {
                    _consoleOutput.WriteLine(value);
                    _streamWriter.WriteLine(value);
            
                }
                public override void WriteLine(object value)
                {
                    _consoleOutput.WriteLine(value);
                    _streamWriter.WriteLine(value);
            
                }
                public override void WriteLine(float value)
                {
                    _consoleOutput.WriteLine(value);
                    _streamWriter.WriteLine(value);
            
                }
                public override void WriteLine(bool value)
                {
                    _consoleOutput.WriteLine(value);
                    _streamWriter.WriteLine(value);
            
                }
                public override void WriteLine(uint value)
                {
                    _consoleOutput.WriteLine(value);
                    _streamWriter.WriteLine(value);
            
                }
                public override void WriteLine(long value)
                {
                    _consoleOutput.WriteLine(value);
                    _streamWriter.WriteLine(value);
            
                }
                public override void WriteLine(ulong value)
                {
                    _consoleOutput.WriteLine(value);
                    _streamWriter.WriteLine(value);
            
                }
                public override void WriteLine(int value)
                {
                    _consoleOutput.WriteLine(value);
                    _streamWriter.WriteLine(value);
            
                }
                public override void WriteLine(char[] buffer)
                {
                    _consoleOutput.WriteLine(buffer);
                    _streamWriter.WriteLine(buffer);
            
                }
                public override void WriteLine(char value)
                {
                    _consoleOutput.WriteLine(value);
                    _streamWriter.WriteLine(value);
            
                }
                public override void WriteLine(string format, params object[] arg)
                {
                    _consoleOutput.WriteLine(format, arg);
                    _streamWriter.WriteLine(format, arg);
            
                }
                public override void WriteLine(string format, object arg0)
                {
                    _consoleOutput.WriteLine(format, arg0);
                    _streamWriter.WriteLine(format, arg0);
            
                }
                public override void WriteLine(string format, object arg0, object arg1)
                {
                    _consoleOutput.WriteLine(format, arg0, arg1);
                    _streamWriter.WriteLine(format, arg0, arg1);
            
                }
                public override void WriteLine(char[] buffer, int index, int count)
                {
                    _consoleOutput.WriteLine(buffer, index, count);
                    _streamWriter.WriteLine(buffer, index, count);
            
                }
                public override void WriteLine(string format, object arg0, object arg1, object arg2)
                {
                    _consoleOutput.WriteLine(format, arg0, arg1, arg2);
                    _streamWriter.WriteLine(format, arg0, arg1, arg2);
            
                }
            
                protected override void Dispose(bool disposing)
                {
                    if (disposing)
                    {
                        Console.SetOut(_consoleOutput);
                        Console.SetError(_consoleError);
                    }
                }
            }
            

            【讨论】:

              【解决方案13】:

              您实际上可以通过实现您自己的继承自 TextWriter 的类并覆盖 WriteLine 方法来创建 Console.Out 到 Trace 的透明镜像。

              在 WriteLine 中,您可以将其写入 Trace,然后可以将其配置为写入文件。

              我发现这个答案很有帮助: https://stackoverflow.com/a/10918320/379132

              它确实对我有用!

              【讨论】:

                【解决方案14】:

                我的答案是基于most-voted non-accepted answerleast-voted answer,我认为这是迄今为止最优雅的解决方案。就您可以使用的流类型而言,它更通用一些(例如,您可以使用MemoryStream),但为了简洁起见,我省略了latter answer 中包含的所有扩展功能。

                class ConsoleMirrorWriter : TextWriter
                {
                    private readonly StreamWriter _writer;
                    private readonly TextWriter _consoleOut;
                
                    public ConsoleMirrorWriter(Stream stream)
                    {
                        _writer = new StreamWriter(stream);
                        _consoleOut = Console.Out;
                        Console.SetOut(this);
                    }
                
                    public override Encoding Encoding => _writer.Encoding;
                
                    public override void Flush()
                    {
                        _writer.Flush();
                        _consoleOut.Flush();
                    }
                
                    public override void Write(char value)
                    {
                        _writer.Write(value);
                        _consoleOut.Write(value);
                    }
                
                    protected override void Dispose(bool disposing)
                    {
                        if (!disposing) return;
                        _writer.Dispose();
                        Console.SetOut(_consoleOut);
                    }
                }
                

                用法:

                using (var stream = File.Create(Path.Combine(Path.GetTempPath(), AppDomain.CurrentDomain.FriendlyName)))
                using (var writer = new ConsoleMirrorWriter(stream))
                {
                    // Code using console output.
                }
                

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2021-10-21
                  • 2023-03-27
                  • 2021-06-05
                  • 2022-12-04
                  相关资源
                  最近更新 更多