it-swarm.com.de

Konsolenausgabe in eine Datei spiegeln

Gibt es in einer C # -Konsolenanwendung eine intelligente Möglichkeit, die Konsolenausgabe in eine Textdatei zu spiegeln?

Zur Zeit übergebe ich nur den gleichen String an Console.WriteLine und InstanceOfStreamWriter.WriteLine in einer Protokollmethode.

84
xyz

Das mag etwas mehr Arbeit sein, aber ich würde den umgekehrten Weg gehen.

Instanziieren Sie eine TraceListener für die Konsole und eine für die Protokolldatei. Verwenden Sie anschließend Trace.Write-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, sodass Sie die Protokollierung aktivieren oder deaktivieren können, ohne den Build zu berühren.

109

Dies ist eine einfache Klasse, die TextWriter für die Umleitung der Eingabe an eine Datei und an die Konsole einsetzt.

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;
    }
  }

}
42
Christian

Check out log4net . Mit log4net können Sie Konsolen- und Datei-Appender einrichten, die Protokollnachrichten mit einer einzigen Protokollanweisung an beide Stellen ausgeben können.

13
tvanfosson

Sie können die TextWriter-Klasse subclassieren und dann ihre Instanz der Console.Out mit der Methode Console.SetOut zuordnen. Diese Methode führt insbesondere dazu, dass beide Methoden in der Protokollmethode denselben String übergeben.

Eine andere Möglichkeit könnte Ihre eigene Console-Klasse deklarieren und die using-Anweisung verwenden, um zwischen den Klassen zu unterscheiden:

using Console = My.Very.Own.Little.Console;

Für den Zugriff auf die Standardkonsole benötigen Sie dann:

global::Console.Whatever
8
arul

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 von tee zu finden, die die Ausgabe in eine Datei aufteilt.

7
xtofl

Da ich von hier aus so viel gelernt habe, muss ich wirklich meine Lösung hier teilen. 

Zuerst müssen wir eine neue Klasse erstellen, die von StreamWriter inhärent ist, beispielsweise CombinedWriter.

Starten Sie dann einen neuen Zeitpunkt von CombinedWriter mit Console.Out;

Schließlich können wir die Konsolenausgabe mit Console.SetOut auf den Moment der neuen Klasse umleiten.

Folgender Code ist die neue Klasse, die für mich funktioniert.

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 Write(string value)
    {
        console.Write(value);
        base.Write(value);
    }
}
7
Keep Thinking

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, an die Datei oder an beides gesendet wird.

6
kgiannakakis

Wie von Arul vorgeschlagen, können Sie mit Console.SetOut die Ausgabe in eine Textdatei umleiten:

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

Ich denke, was Sie bereits verwenden, ist gewissermaßen der beste Ansatz. Eine einfache Methode zum Spiegeln Ihrer Ausgabe.

Zuerst deklarieren Sie am Anfang einen globalen TextWriter:

private TextWriter txtMirror = new StreamWriter("mirror.txt");

Dann mache 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 anstelle von Console.WriteLine("...");Log("...");. So einfach ist das. Es ist noch kürzer!


Es kann Probleme geben, wenn Sie die Cursorposition verschieben (Console.SetCursorPosition(x, y);), aber ansonsten funktioniert es gut, ich verwende es auch selbst!

BEARBEITEN

Natürlich können Sie eine Methode für Console.Write(); genauso erstellen, wenn Sie nicht nur WriteLines verwenden

4
Richard de Wit

Die Entscheidung, eine Klasse zu verwenden, die vom StreamWriter geerbt wurde, Vorschläge vom Benutzer Keep Thinking, funktioniert. Aber ich musste den Konstruktor base.AutoFlush = true hinzufügen

{
    this.console = console;
    base.AutoFlush = true;
}

und einen expliziten 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);
2
konoplinovich

Vielen Dank für die hervorragende Lösung! Ich habe einige weitere Überschreibungen hinzugefügt, um das Protokollieren bestimmter Schreibereignisse der Konsole zu vermeiden, 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();
        }
    }
}
2
user2789183

Wenn Sie die Konsolenausgabe eines Codes kopieren, den Sie nicht steuern, z. B. die Bibliothek eines Drittanbieters, sollten alle Mitglieder von TextWriter überschrieben werden. Der Code verwendet Ideen aus diesem Thread. 

Verwendungszweck:

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);
        }
    }
}
0
Crabba

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 für das Schreiben in eine Datei konfiguriert werden kann.

Ich fand diese Antwort sehr hilfreich: https://stackoverflow.com/a/10918320/379132

Es hat tatsächlich für mich funktioniert!

0
Sushil

Meine Antwort basiert auf der am meisten gestimmten nicht akzeptierten Antwort und auch der am wenigsten gestimmten Antwort , die meiner Meinung nach die eleganteste Lösung ist. Es ist etwas allgemeiner in Bezug auf den Stream-Typ, den Sie verwenden können (Sie können beispielsweise MemoryStream verwenden), aber ich habe alle erweiterten Funktionen ausgelassen, die in letztere Antwort für enthalten sind Kürze.

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

Verwendungszweck:

using (var stream = File.Create(Path.Combine(Path.GetTempPath(), AppDomain.CurrentDomain.FriendlyName)))
using (var writer = new ConsoleMirrorWriter(stream))
{
    // Code using console output.
}
0
Neo