如何保存控制台应用程序的输出
我需要有关如何让我的 C# 控制台应用程序通过标准输出向用户显示文本,同时仍然能够稍后访问它的建议。 我想要实现的实际功能是在程序执行结束时将整个输出缓冲区转储到文本文件中。
当我找不到更干净的方法时,我使用的解决方法是子类 TextWriter
覆盖写入方法,以便它们既写入文件又调用原始的标准输出编写器。 像这样的事情:
public class DirtyWorkaround {
private class DirtyWriter : TextWriter {
private TextWriter stdoutWriter;
private StreamWriter fileWriter;
public DirtyWriter(string path, TextWriter stdoutWriter) {
this.stdoutWriter = stdoutWriter;
this.fileWriter = new StreamWriter(path);
}
override public void Write(string s) {
stdoutWriter.Write(s);
fileWriter.Write(s);
fileWriter.Flush();
}
// Same as above for WriteLine() and WriteLine(string),
// plus whatever methods I need to override to inherit
// from TextWriter (Encoding.Get I guess).
}
public static void Main(string[] args) {
using (DirtyWriter dw = new DirtyWriter("path", Console.Out)) {
Console.SetOut(dw);
// Teh codez
}
}
}
查看它始终写入并刷新文件。 我只想在执行结束时执行此操作,但我找不到任何访问输出缓冲区的方法。
另外,请原谅上述代码的不准确之处(不得不临时编写它,抱歉;)。
I need advice on how to have my C# console application display text to the user through the standard output while still being able access it later on. The actual feature I would like to implement is to dump the entire output buffer to a text file at the end of program execution.
The workaround I use while I don't find a cleaner approach is to subclass TextWriter
overriding the writing methods so they would both write to a file and call the original stdout writer. Something like this:
public class DirtyWorkaround {
private class DirtyWriter : TextWriter {
private TextWriter stdoutWriter;
private StreamWriter fileWriter;
public DirtyWriter(string path, TextWriter stdoutWriter) {
this.stdoutWriter = stdoutWriter;
this.fileWriter = new StreamWriter(path);
}
override public void Write(string s) {
stdoutWriter.Write(s);
fileWriter.Write(s);
fileWriter.Flush();
}
// Same as above for WriteLine() and WriteLine(string),
// plus whatever methods I need to override to inherit
// from TextWriter (Encoding.Get I guess).
}
public static void Main(string[] args) {
using (DirtyWriter dw = new DirtyWriter("path", Console.Out)) {
Console.SetOut(dw);
// Teh codez
}
}
}
See that it writes to and flushes the file all the time. I'd love to do it only at the end of the execution, but I couldn't find any way to access to the output buffer.
Also, excuse inaccuracies with the above code (had to write it ad hoc, sorry ;).
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
完美的解决方案是将 log4net 与控制台附加器和文件附加器一起使用。 还有许多其他附加程序可用。 它还允许您在运行时关闭和打开不同的附加程序。
The perfect solution for this is to use log4net with a console appender and a file appender. There are many other appenders available as well. It also allows you to turn the different appenders off and on at runtime.
我不认为你的做法有什么问题。
如果您想要可重用的代码,请考虑实现一个名为
MultiWriter
的类或类似的类,该类将两个(或 N?)TextWriter
流作为输入,并将所有命令、刷新等分发到那些溪流。 然后你可以做这个文件/控制台的事情,但你也可以轻松地分割任何输出流。 有用!I don't think there's anything wrong with your approach.
If you wanted reusable code, consider implementing a class called
MultiWriter
or somesuch that takes as input two (or N?)TextWriter
streams and distributes all writs, flushes, etc. to those streams. Then you can do this file/console thing, but just as easily you can split any output stream. Useful!可能不是你想要的,但以防万一......显然, PowerShell 实现了 古老的
tee
命令的一个版本。 这几乎就是为了这个目的。 所以...如果你有的话就抽吧。Probably not what you want, but just in case... Apparently, PowerShell implements a version of the venerable
tee
command. Which is pretty much intended for exactly this purpose. So... smoke 'em if you got 'em.我想说的是模仿 .NET 本身使用的诊断(跟踪和调试)。
创建一个“输出”类,该类可以具有遵循文本输出接口的不同类。 您向输出类报告,它会自动将给定的输出发送给您添加的类(ConsoleOutput、TextFileOutput、WhateverOutput)......等等......这也让您可以添加其他“输出”类型(例如 xml/ xslt 以获得格式良好的报告?)。
查看跟踪侦听器集合以了解我的意思。
I would say mimic the diagnostics that .NET itself uses (Trace and Debug).
Create a "output" class that can have different classes that adhere to a text output interface. You report to the output class, it automatically sends the output given to the classes you have added (ConsoleOutput, TextFileOutput, WhateverOutput).. And so on.. This also leaves you open to add other "output" types (such as xml/xslt to get a nicely formatted report?).
Check out the Trace Listeners Collection to see what I mean.
考虑重构您的应用程序,将用户交互部分与业务逻辑分开。 根据我的经验,这样的分离对于程序的结构非常有利。
对于您在此处尝试解决的特定问题,用户交互部分将其行为从
Console.WriteLine
更改为文件 I/O 变得非常简单。Consider refactoring your application to separate the user-interaction portions from the business logic. In my experience, such a separation is quite beneficial to the structure of your program.
For the particular problem you're trying to solve here, it becomes straightforward for the user-interaction part to change its behavior from
Console.WriteLine
to file I/O.我正在努力实现类似的功能来捕获发送到控制台的输出并将其保存到日志中,同时仍然将输出实时传递到普通控制台,这样它就不会破坏应用程序(例如,如果它是控制台应用程序) !)。
如果您仍然尝试通过保存控制台输出在自己的代码中执行此操作(而不是使用日志系统仅保存您真正关心的信息),我认为您可以避免每次写入后的刷新,只要因为您还重写了 Flush() 并确保它刷新了您保存的原始
stdoutWriter
以及您的fileWriter
。 您需要执行此操作,以防应用程序尝试将部分行刷新到控制台以立即显示(例如输入提示、进度指示器等),以覆盖正常的行缓冲。如果该方法存在控制台输出缓冲时间过长的问题,您可能需要确保 WriteLine() 刷新
stdoutWriter
(但可能不需要刷新fileWriter
除非调用 Flush() 重写时)。 但我认为原始的Console.Out(实际上进入控制台)会在换行符上自动刷新其缓冲区,因此您不必强制它。您可能还想重写 Close() 来(刷新并)关闭您的
fileWriter
(也可能是stdoutWriter
),但我不确定这是否真的需要或如果基本 TextWriter 中的 Close() 会发出 Flush() (您已经覆盖它),并且您可能依赖应用程序退出来关闭文件。 当然,您应该测试它在退出时是否被刷新。 请注意,异常退出(崩溃)可能不会刷新缓冲的输出。 如果这是一个问题,在换行符上刷新fileWriter
可能是可取的,但这是另一个需要解决的棘手蠕虫问题。I'm working on implementing a similar feature to capture output sent to the Console and save it to a log while still passing the output in real time to the normal Console so it doesn't break the application (eg. if it's a console application!).
If you're still trying to do this in your own code by saving the console output (as opposed to using a logging system to save just the information you really care about), I think you can avoid the flush after each write, as long as you also override Flush() and make sure it flushes the original
stdoutWriter
you saved as well as yourfileWriter
. You want to do this in case the application is trying to flush a partial line to the console for immediate display (such as an input prompt, a progress indicator, etc), to override the normal line-buffering.If that approach has problems with your console output being buffered too long, you might need to make sure that WriteLine() flushes
stdoutWriter
(but probably doesn't need to flushfileWriter
except when your Flush() override is called). But I would think that the originalConsole.Out
(actually going to the console) would automatically flush its buffer upon a newline, so you shouldn't have to force it.You might also want to override Close() to (flush and) close your
fileWriter
(and probablystdoutWriter
as well), but I'm not sure if that's really needed or if a Close() in the base TextWriter would issue a Flush() (which you would already override) and you might rely on application exit to close your file. You should probably test that it gets flushed on exit, to be sure. And be aware that an abnormal exit (crash) likely won't flush buffered output. If that's an issue, flushingfileWriter
on newline may be desirable, but that's another tricky can of worms to work out.