Есть ли в консольном приложении C # разумный способ зеркального отображения вывода консоли в текстовый файл?
В настоящее время я просто передаю одну и ту же строку обоим Console.WriteLine
и InstanceOfStreamWriter.WriteLine
в методе журнала.
Это может быть еще какая-то работа, но я бы пошел наоборот.
Создайте экземпляр 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.
This is a simple class which subclasses TextWriter to allow redirection of the input to both a file and the console.
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; } } }
источник
Console.WriteLine()
, which was exactly what I wanted.Console.SetOut(doubleWriter);
. Which is modifying a global for Console, It took me a bit, since I'm so used to working in applications where practically nothing is global. Good stuff!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.
источник
Can't you just redirect the output to a file, using the
>
command?If you need to mirror, you can try find a win32 version of
tee
that splits the output to a file.See /superuser/74127/tee-for-windows to run tee from PowerShell
источник
You could subclass the TextWriter class, and then assign its instance to the Console.Out using the Console.SetOut method - which in particular does the same thing as passing the same string to both methods in the log method.
Another way might declaring your own Console class and use the using statement to distinguish between the classes:
using Console = My.Very.Own.Little.Console;
To access the standard console you'd then need:
global::Console.Whatever
источник
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.
First we need to create new class inherent from StreamWriter, say CombinedWriter;
Then init a new instant of CombinedWriter with Console.Out;
Finally we can redirect console output to the instant of the new class by 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); } }
источник
public override void Write(char value);
,public override void Write(char[] buffer);
,public override void Write(string value);
andpublic override void Write(char[] buffer, int index, int count);
. Otherwise it does not print to console if you useWriteLine(format, ...)
method.Log4net can do this for you. You would only write something like this:
logger.info("Message");
A configuration will determine whether the print out will go to console, file or both.
источник
I think what you already are using is kind of the best approach. A simple method to essentially mirror your output.
First declare a global TextWriter at the beginning:
private TextWriter txtMirror = new StreamWriter("mirror.txt");
Then make a method for writing:
// Write empty line private void Log() { Console.WriteLine(); txtMirror.WriteLine(); } // Write text private void Log(string strText) { Console.WriteLine(strText); txtMirror.WriteLine(strText); }
Now, instead of using
Console.WriteLine("...");
, useLog("...");
. Simple as that. It's even shorter!There could be some trouble if you shift the cursorposition (
Console.SetCursorPosition(x, y);
), but otherwise works well, I use it myself too!EDIT
Ofcourse you can make a method for
Console.Write();
the same way if you're not using only WriteLinesисточник
As suggested by Arul, using
Console.SetOut
can be used to redirect output to a text file:Console.SetOut(new StreamWriter("Output.txt"));
источник
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:
{ 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);
источник
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.
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(); } } }
источник
If you duplicate console output from a code you do not control, for example 3rd party library, all members of TextWriter should be overwritten. The code uses ideas from this thread.
Usage:
using (StreamWriter writer = new StreamWriter(filePath)) { using (new ConsoleMirroring(writer)) { // code using console output } }
ConsoleMirroring class
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); } } }
источник
You can actually create a transparent mirroring of Console.Out to Trace by implementing your own class inherited from TextWriter and overriding WriteLine method.
In WriteLine you can write it to Trace which can then be configured to write to file.
I found this answer very helpful: https://stackoverflow.com/a/10918320/379132
It actually worked for me!
источник
My answer is based on the most-voted non-accepted answer, and also the least-voted answer which I think is the most elegant solution so far. It's a little more generic in terms of the stream type you can use (you may use a
MemoryStream
for instance), but I've omitted all the extended functionality included in the latter answer for brevity.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); } }
Usage:
using (var stream = File.Create(Path.Combine(Path.GetTempPath(), AppDomain.CurrentDomain.FriendlyName))) using (var writer = new ConsoleMirrorWriter(stream)) { // Code using console output. }
источник