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