C# 将控制台输出镜像到文件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/420429/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-04 02:42:18  来源:igfitidea点击:

Mirroring console output to a file

c#.netfiletextconsole

提问by xyz

In a C# console application, is there a smart way to have console output mirrored to a text file?

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

Currently I am just passing the same string to both Console.WriteLineand InstanceOfStreamWriter.WriteLinein a log method.

目前,我只是路过相同的字符串既Console.WriteLineInstanceOfStreamWriter.WriteLine在日志方法。

采纳答案by Oliver Friedrich

This may be some kind of more work, but I would go the other way round.

这可能需要更多的工作,但我会反其道而行之。

Instantiate a TraceListenerfor the console and one for the log file; thereafter use Trace.Writestatements in your code instead of Console.Write. It becomes easier afterwards to remove the log, or the console output, or to attach another logging mechanism.

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.");
}

As far as I can recall, you can define the listeners in the application configuration making it possible to activate or deactivate the logging without touching the build.

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

回答by tvanfosson

Check out log4net. With log4net you can set up console and file appenders that will can output log messages to both places with a single log statement.

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

回答by kgiannakakis

Log4netcan do this for you. You would only write something like this:

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

logger.info("Message");

A configuration will determine whether the print out will go to console, file or both.

配置将确定打印输出是进入控制台、文件还是两者。

回答by arul

You could subclass the TextWriter class, and then assign its instance to the Console.Out using the Console.SetOutmethod - which in particular does the same thing as passing the same string to both methods in the log method.

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

Another way might declaring your own Console class and use the using statement to distinguish between the classes:

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

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

To access the standard console you'd then need:

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

global::Console.Whatever

回答by xtofl

Can't you just redirect the output to a file, using the >command?

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

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

If you need to mirror, you can try find a win32 version of teethat splits the output to a file.

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

See https://superuser.com/questions/74127/tee-for-windowsto run teefrom PowerShell

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

回答by Christian

This is a simple class which subclasses TextWriter to allow redirection of the input to both a file and the console.

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

Use it like this

像这样使用它

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

Here is the class:

这是课程:

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;
    }
  }

}

回答by hgirish

As suggested by Arul, using Console.SetOutcan be used to redirect output to a text file:

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

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

回答by Keep Thinking

EDIT: This method provide the possibility to redirect the console information come from third party package. override the WriteLine method is good for my situation, but you may need to override other Write methods depends on the third party package.

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

First we need to create new class inherent from StreamWriter, say CombinedWriter;

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

Then init a new instant of CombinedWriter with Console.Out;

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

Finally we can redirect console output to the instant of the new class by Console.SetOut;

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

Following code is the new class works for me.

以下代码是对我有用的新课程。

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);
    }
}

回答by konoplinovich

The decision to use a class, inherited from the StreamWriter, suggestions by user Keep Thinking, works. But I had to to add into constructor base.AutoFlush = true:

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

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

аnd an explicit call to the destructor:

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

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

Otherwise, the file is closed earlier than he recorded all the data.

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

I am using it as:

我将它用作:

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

回答by user2789183

Thank you to Keep Thinking for the excellent solution! I added some further overrides to avoid logging certain console write events that (for my purposes) are only expected for console display.

感谢 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();
        }
    }
}