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

C# 将控制台输出镜像到文件,c#,.net,file,text,console,C#,.net,File,Text,Console,在C#console应用程序中,是否有一种聪明的方法将控制台输出镜像到文本文件 目前,我只是在日志方法中将相同的字符串传递给控制台.WriteLine和实例流写入器.WriteLine。签出。使用log4net,您可以设置控制台和文件附加器,这些附加器可以使用一条日志语句将日志消息输出到两个位置。可以为您完成这项工作。你只能这样写: logger.info("Message"); 配置将确定打印输出是转到控制台、文件还是同时转到两者。您可以对TextWriter类进行子类化,然后使用该方法将其

在C#console应用程序中,是否有一种聪明的方法将控制台输出镜像到文本文件

目前,我只是在日志方法中将相同的字符串传递给
控制台.WriteLine
实例流写入器.WriteLine

签出。使用log4net,您可以设置控制台和文件附加器,这些附加器可以使用一条日志语句将日志消息输出到两个位置。

可以为您完成这项工作。你只能这样写:

logger.info("Message");

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

您可以对TextWriter类进行子类化,然后使用该方法将其实例分配给console.out,该方法的作用与在log方法中将相同的字符串传递给这两个方法相同

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

using Console = My.Very.Own.Little.Console;
要访问标准控制台,您需要:

global::Console.Whatever

这可能是更多的工作,但我会走另一条路

为控制台实例化一个
TraceListener
,为日志文件实例化一个;然后使用
跟踪。在代码中写入
语句,而不是
控制台。写入
。之后,删除日志、控制台输出或附加另一个日志机制变得更加容易

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

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

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

c:\>Console.exe > c:/temp/output.txt
如果需要镜像,可以尝试查找win32版本的
tee
,将输出拆分为文件


请参阅从PowerShell运行tee这是一个简单的类,它将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;
    }
  }

}

正如Arul所建议的,使用控制台设置可以将输出重定向到文本文件:

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

编辑:此方法提供了重定向来自第三方包的控制台信息的可能性。重写WriteLine方法适合我的情况,但您可能需要重写其他写入方法,具体取决于第三方软件包

首先,我们需要从StreamWriter(比如CombinedWriter)中创建新的固有类

然后初始化一个带有控制台的CombinedWriter.Out的新瞬间

最后,我们可以通过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);
    }
}

使用从StreamWriter继承的类的决定,以及用户不断思考的建议,都是有效的。 但我必须添加到构造函数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);

感谢您不断思考这个优秀的解决方案!我添加了一些进一步的覆盖,以避免记录某些控制台写入事件,这些事件(出于我的目的)仅用于控制台显示

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();
        }
    }
}
使用系统;
使用System.IO;
使用System.Collections.Generic;
使用System.Linq;
使用系统文本;
命名空间重定向输出
{
公共类组合编写器:StreamWriter
{
文本编写器控制台;
公共组合编写器(字符串路径、布尔追加、TextWriter控制台输出)
:base(路径,附加)
{
this.console=consoleout;
base.AutoFlush=true;
}
公共重写无效写入(字符串值)
{
控制台。写入(值);
//base.Write(value);//不要记录没有行尾的写入操作,因为这些操作仅用于控制台显示
}
公共覆盖无效写入线()
{
console.WriteLine();
//base.WriteLine();//不要记录空写入,因为这些仅用于高级控制台显示
}
公共重写无效写线(字符串值)
{
控制台写入线(值);
如果(值!=“”)
{
基本写入线(值);
}
}
公开新的无效处置()
{
base.Dispose();
}
}
班级计划
{
静态void Main(字符串[]参数)
{
CombinedWriter cw=新的CombinedWriter(“combined.log”,false,Console.Out);
控制台放线(cw);
控制台写入线(“第1行”);
Console.WriteLine();
控制台写入线(“第2行”);
控制台。写线(“”);
对于(int i=0;i<10;i++)
{
Console.Write(“Waiting”+i.ToString());
Console.CursorLeft=0;
}
Console.WriteLine();
对于(int i=0;i<10;i++)
{
Console.Write(“Waiting”+i.ToString());
}
Console.WriteLine();
控制台写入线(“第3行”);
cw.Dispose();
}
}
}

我认为您已经在使用的是最好的方法。一个简单的方法,基本上镜像您的输出

首先在开头声明一个全局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(“…”),使用
日志(“…”)。就这么简单。它甚至更短


如果您移动光标位置(
Console.SetCursorPosition(x,y);
),可能会出现一些问题,但如果其他操作正常,我也会自己使用它

编辑
当然,您可以为
Console.Write()创建一个方法同样的方法,如果您不只是使用WriteLines,您实际上可以通过实现您自己从TextWriter继承的类并重写WriteLine方法来创建Console.Out的透明镜像以进行跟踪

在WriteLine中,您可以将其写入Trace,然后
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.
}