web-dev-qa-db-fra.com

Mise en miroir de la sortie de la console dans un fichier

Dans une application console C #, existe-t-il un moyen astucieux de mettre la sortie de la console en miroir dans un fichier texte?

Actuellement, je passe juste la même chaîne à Console.WriteLine et InstanceOfStreamWriter.WriteLine dans une méthode de journalisation.

84
xyz

C'est peut-être une sorte de travail supplémentaire, mais j'irais dans l'autre sens.

Instanciez une TraceListener pour la console et une pour le fichier journal; Utilisez ensuite les instructions Trace.Write dans votre code au lieu de Console.Write. Il devient ensuite plus facile de supprimer le journal ou la sortie de la console ou d’attacher un autre mécanisme de journalisation.

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

Autant que je me souvienne, vous pouvez définir les écouteurs dans la configuration de l'application, ce qui permet d'activer ou de désactiver la journalisation sans toucher à la construction.

109
Oliver Friedrich

Il s'agit d'une classe simple qui sous-classe TextWriter pour permettre la redirection de l'entrée vers un fichier et la console.

Utilisez-le comme ça

  using (var cc = new ConsoleCopy("mylogfile.txt"))
  {
    Console.WriteLine("testing 1-2-3");
    Console.WriteLine("testing 4-5-6");
    Console.ReadKey();
  }

Voici la classe:

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

Départ log4net . Avec log4net, vous pouvez configurer des appenders pour la console et les fichiers qui peuvent envoyer des messages de journal aux deux endroits avec une seule instruction de journal.

13
tvanfosson

Vous pouvez sous-classer la classe TextWriter, puis attribuer son instance à Console.Out à l'aide de la méthode Console.SetOut - qui fait en particulier la même chose que de transmettre la même chaîne aux deux méthodes de la méthode log.

Une autre manière peut déclarer votre propre classe de console et utiliser l’instruction using pour distinguer les classes:

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

Pour accéder à la console standard, vous devez ensuite:

global::Console.Whatever
8
arul

Ne pouvez-vous pas simplement rediriger la sortie vers un fichier en utilisant la commande >?

c:\>Console.exe > c:/temp/output.txt

Si vous devez mettre en miroir, vous pouvez rechercher une version win32 de tee qui divise la sortie en fichier.

7
xtofl

Comme j'ai beaucoup appris d'ici, j'ai vraiment besoin de partager ma solution ici. 

Tout d'abord, nous devons créer une nouvelle classe inhérente à StreamWriter, dit CombinedWriter;

Puis initiez un nouvel instant de CombinedWriter avec Console.Out;

Enfin, nous pouvons rediriger la sortie de la console vers l'instant de la nouvelle classe par Console.SetOut;

Le code suivant est la nouvelle classe qui fonctionne pour moi.

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 peut le faire pour vous. Vous n'écririez que quelque chose comme ceci:

logger.info("Message");

Une configuration déterminera si l'impression sortira sur la console, le fichier ou les deux.

6
kgiannakakis

Comme suggéré par Arul, Console.SetOut peut être utilisé pour rediriger la sortie vers un fichier texte:

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

Je pense que ce que vous utilisez déjà est en quelque sorte la meilleure approche. Une méthode simple pour refléter essentiellement votre sortie.

Commençons par déclarer un TextWriter global au début:

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

Ensuite, créez une méthode pour écrire:

// Write empty line
private void Log()
{
    Console.WriteLine();
    txtMirror.WriteLine();
}

// Write text
private void Log(string strText)
{
    Console.WriteLine(strText);
    txtMirror.WriteLine(strText);
}

Maintenant, au lieu d'utiliser Console.WriteLine("...");, utilisez Log("...");. Aussi simple que cela. C'est encore plus court!


Il pourrait y avoir un problème si vous déplacez la position du curseur (Console.SetCursorPosition(x, y);), mais sinon ça marche bien, je l’utilise moi aussi!

MODIFIER

Bien sûr, vous pouvez créer une méthode pour Console.Write(); de la même manière si vous n'utilisez pas uniquement WriteLines

4
Richard de Wit

La décision d'utiliser une classe, héritée de StreamWriter, des suggestions de l'utilisateur Keep Thinking, fonctionne . Mais je devais ajouter au constructeur base.AutoFlush = true:

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

et un appel explicite au destructeur:

public new void Dispose ()
{
    base.Dispose ();
}

Sinon, le fichier est fermé plus tôt qu'il a enregistré toutes les données.

Je l'utilise comme:

CombinedWriter cw = new CombinedWriter ( "out.txt", true, Encoding.Unicode, 512, Console.Out );
Console.SetOut (cw);
2
konoplinovich

Merci de continuer à penser pour l'excellente solution! J'ai ajouté quelques substitutions supplémentaires pour éviter de consigner certains événements d'écriture sur la console qui (pour mes besoins) ne sont attendus que pour l'affichage de la console.

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

Si vous dupliquez la sortie de la console à partir d'un code que vous ne contrôlez pas, par exemple une bibliothèque tierce, tous les membres de TextWriter doivent être écrasés. Le code utilise des idées de ce fil. 

Usage:

using (StreamWriter writer = new StreamWriter(filePath))
{
   using (new ConsoleMirroring(writer))
   {
       // code using console output
   }
}

Classe ConsoleMirroring

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

Vous pouvez réellement créer une copie transparente de Console.Out to Trace en implémentant votre propre classe héritée de TextWriter et en substituant la méthode WriteLine. 

Dans WriteLine, vous pouvez l'écrire dans Trace, qui peut ensuite être configuré pour écrire dans un fichier.

J'ai trouvé cette réponse très utile: https://stackoverflow.com/a/10918320/379132

Cela a réellement fonctionné pour moi!

0
Sushil

Ma réponse est basée sur le réponse non acceptée le plus voté , ainsi que sur le réponse la moins votée qui, à mon avis, est la solution la plus élégante à ce jour. C'est un peu plus générique en termes de type de flux que vous pouvez utiliser (vous pouvez utiliser un MemoryStream par exemple), mais j'ai omis toutes les fonctionnalités étendues incluses dans le dernière réponse pour brièveté.

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.
}
0
Neo