Antworten:
Dies mag eine Art mehr Arbeit sein, aber ich würde den umgekehrten Weg gehen.
Instanziieren Sie a TraceListener
für die Konsole und eins für die Protokolldatei. Verwenden Trace.Write
Sie danach Anweisungen in Ihrem Code anstelle von Console.Write
. Danach wird es einfacher, das Protokoll oder die Konsolenausgabe zu entfernen oder einen anderen Protokollierungsmechanismus anzuhängen.
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.");
}
Soweit ich mich erinnern kann, können Sie die Listener in der Anwendungskonfiguration definieren, um die Protokollierung zu aktivieren oder zu deaktivieren, ohne den Build zu berühren.
Dies ist eine einfache Klasse, die TextWriter in Unterklassen unterteilt, um die Umleitung der Eingabe sowohl in eine Datei als auch in die Konsole zu ermöglichen.
Verwenden Sie es so
using (var cc = new ConsoleCopy("mylogfile.txt"))
{
Console.WriteLine("testing 1-2-3");
Console.WriteLine("testing 4-5-6");
Console.ReadKey();
}
Hier ist die Klasse:
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()
, was genau das war, was ich wollte.
Console.SetOut(doubleWriter);
. Was eine globale Konsole modifiziert, hat mich ein bisschen gekostet, da ich es so gewohnt bin, in Anwendungen zu arbeiten, in denen praktisch nichts global ist. Gutes Zeug!
Schauen Sie sich log4net an . Mit log4net können Sie Konsolen- und Dateianhänge einrichten, die Protokollnachrichten mit einer einzigen Protokollanweisung an beide Stellen ausgeben können.
Können Sie die Ausgabe nicht einfach mit dem >
Befehl in eine Datei umleiten ?
c:\>Console.exe > c:/temp/output.txt
Wenn Sie spiegeln müssen, können Sie versuchen, eine Win32-Version zu finden tee
, die die Ausgabe in eine Datei aufteilt.
Unter /superuser/74127/tee-for-windows können Sie Tee von PowerShell ausführen
Sie können die TextWriter-Klasse in Unterklassen unterteilen und dann ihre Instanz der Console.Out mithilfe der Console.SetOut- Methode zuweisen. Dies entspricht insbesondere der Übergabe derselben Zeichenfolge an beide Methoden in der Protokollmethode.
Eine andere Möglichkeit besteht darin, Ihre eigene Konsolenklasse zu deklarieren und die using-Anweisung zu verwenden, um zwischen den Klassen zu unterscheiden:
using Console = My.Very.Own.Little.Console;
Um auf die Standardkonsole zuzugreifen, benötigen Sie dann:
global::Console.Whatever
BEARBEITEN: Diese Methode bietet die Möglichkeit, die Konsoleninformationen aus dem Paket eines Drittanbieters umzuleiten. Das Überschreiben der WriteLine-Methode ist gut für meine Situation, aber Sie müssen möglicherweise andere Write-Methoden überschreiben, abhängig vom Paket eines Drittanbieters.
Zuerst müssen wir eine neue Klasse erstellen, die StreamWriter innewohnt, z. B. CombinedWriter.
Starten Sie dann einen neuen Moment von CombinedWriter mit Console.Out.
Schließlich können wir die Konsolenausgabe von Console.SetOut auf den Zeitpunkt der neuen Klasse umleiten.
Der folgende Code ist die neue Klasse funktioniert für mich.
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);
und public override void Write(char[] buffer, int index, int count);
. Andernfalls wird nicht auf der Konsole gedruckt, wenn Sie die WriteLine(format, ...)
Methode verwenden.
Log4net kann dies für Sie tun. Sie würden nur so etwas schreiben:
logger.info("Message");
Eine Konfiguration bestimmt, ob der Ausdruck an die Konsole, die Datei oder an beide gesendet wird.
Ich denke, was Sie bereits verwenden, ist der beste Ansatz. Eine einfache Methode, um Ihre Ausgabe im Wesentlichen zu spiegeln.
Deklarieren Sie zunächst einen globalen TextWriter am Anfang:
private TextWriter txtMirror = new StreamWriter("mirror.txt");
Dann machen Sie eine Methode zum Schreiben:
// Write empty line
private void Log()
{
Console.WriteLine();
txtMirror.WriteLine();
}
// Write text
private void Log(string strText)
{
Console.WriteLine(strText);
txtMirror.WriteLine(strText);
}
Verwenden Sie jetzt anstatt zu Console.WriteLine("...");
verwenden Log("...");
. So einfach ist das. Es ist noch kürzer!
Es könnte Probleme geben, wenn Sie die Cursorposition ( Console.SetCursorPosition(x, y);
) verschieben, aber ansonsten funktioniert es gut, ich benutze es auch selbst!
Natürlich können Sie eine Methode auf Console.Write();
die gleiche Weise erstellen, wenn Sie nicht nur WriteLines verwenden
Die Entscheidung, eine vom StreamWriter geerbte Klasse zu verwenden, Vorschläge des Benutzers Keep Thinking, funktioniert. Aber ich musste zur Konstruktorbasis hinzufügen. AutoFlush = true:
{
this.console = console;
base.AutoFlush = true;
}
Und ein expliziter Aufruf an den Destruktor:
public new void Dispose ()
{
base.Dispose ();
}
Andernfalls wird die Datei früher geschlossen, als er alle Daten aufgezeichnet hat.
Ich benutze es als:
CombinedWriter cw = new CombinedWriter ( "out.txt", true, Encoding.Unicode, 512, Console.Out );
Console.SetOut (cw);
Vielen Dank an Keep Thinking für die hervorragende Lösung! Ich habe einige weitere Überschreibungen hinzugefügt, um zu vermeiden, dass bestimmte Konsolenschreibereignisse protokolliert werden, die (für meine Zwecke) nur für die Konsolenanzeige erwartet werden.
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();
}
}
}
Wenn Sie die Konsolenausgabe von einem Code duplizieren, den Sie nicht steuern, z. B. einer Bibliothek eines Drittanbieters, sollten alle Mitglieder von TextWriter überschrieben werden. Der Code verwendet Ideen aus diesem Thread.
Verwendung:
using (StreamWriter writer = new StreamWriter(filePath))
{
using (new ConsoleMirroring(writer))
{
// code using console output
}
}
ConsoleMirroring-Klasse
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);
}
}
}
Sie können tatsächlich eine transparente Spiegelung von Console.Out to Trace erstellen, indem Sie Ihre eigene Klasse implementieren, die von TextWriter geerbt wurde, und die WriteLine-Methode überschreiben.
In WriteLine können Sie es in Trace schreiben, das dann so konfiguriert werden kann, dass es in eine Datei schreibt.
Ich fand diese Antwort sehr hilfreich: https://stackoverflow.com/a/10918320/379132
Es hat tatsächlich bei mir funktioniert!
Meine Antwort basiert auf der am meisten gewählten nicht akzeptierten Antwort und auch auf der am wenigsten gewählten Antwort, die ich für die eleganteste Lösung halte. Es ist etwas allgemeiner in Bezug auf den Stream-Typ, den Sie verwenden können (Sie können MemoryStream
beispielsweise einen verwenden), aber ich habe der Kürze halber alle erweiterten Funktionen, die in der letztgenannten Antwort enthalten sind, weggelassen .
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);
}
}
Verwendung:
using (var stream = File.Create(Path.Combine(Path.GetTempPath(), AppDomain.CurrentDomain.FriendlyName)))
using (var writer = new ConsoleMirrorWriter(stream))
{
// Code using console output.
}