Konsol çıktısını bir dosyaya yansıtma


89

Bir C # konsol uygulamasında, konsol çıktısının bir metin dosyasına yansıtılmasını sağlamanın akıllı bir yolu var mı?

Şu anda aynı dizeyi her ikisine Console.WriteLineve InstanceOfStreamWriter.WriteLinebir günlük yöntemine geçiriyorum.

Yanıtlar:


119

Bu bir tür daha iş olabilir, ama ben tam tersi olurum.

Bir örneğini TraceListenergünlük dosyası için konsolu ve biri için; daha sonra Trace.Writekodunuzda yerine ifadeler kullanın Console.Write. Daha sonra günlüğü veya konsol çıktısını kaldırmak veya başka bir günlük kaydı mekanizması eklemek daha kolay hale gelir.

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

Hatırlayabildiğim kadarıyla, uygulama yapılandırmasında dinleyicileri tanımlayarak, yapıya dokunmadan günlüğe kaydetmeyi etkinleştirebilir veya devre dışı bırakabilirsiniz.


4
Bu mükemmel - teşekkürler. Log4Net'in farkındaydım ancak böyle bir şey için bir kitaplık almak zorunda kalmak yanlış görünüyor.
xyz

3
Neden Trace'i daha büyük bir anlaşma yapmadıklarını bilmiyorum - bana üretim ölçeğinde günlük kaydı için iyi çalışması gerekiyor gibi görünüyor, ancak herkes bunu yapmak için fazladan bir kitaplık (log4net gibi) kullanmak istiyor.
Coderer

Bu tek yönlü bir aynalamadır. Demek istediğim, etkileşimli bir konsolunuz varsa ve kullanıcıdan bazı veriler alırsanız ve her şeyi bir dosyaya kaydetmek istiyorsanız, bu çözüm çalışmaz. Bu basit gerçeğe rağmen sorum kapandı. Burada: stackoverflow.com/questions/3886895/…
Xaqron

6
Bu çözümü gerçekten beğendim, bu yüzden küçük bir temizlik ve yol boyunca birkaç engelin gözden geçirilmesi ile ilgili hızlı bir blog hazırladım. mcrook.com/2014/11/quick-and-easy-console-logging-trace.html Harika çözüm için teşekkürler :)
Michael Crook

51

Bu, girdinin hem bir dosyaya hem de konsola yeniden yönlendirilmesine izin vermek için TextWriter'ın alt sınıflarını oluşturan basit bir sınıftır.

Bunu böyle kullan

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

İşte sınıf:

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

}

5
Bunun en eksiksiz çözüm olduğunu düşünüyorum. Write / WriteLine yöntemlerinin tüm aşırı yüklemelerini geçersiz kılmaya gerek yoktur ve diğer koda şeffaftır. Dolayısıyla, tüm Konsol etkinliği, başka kodda herhangi bir değişiklik yapılmadan dosyaya kopyalanacaktır.
papadi

3
Teşekkürler dostum! Bu harika! Sadece yerini File.Create tarafından File.Open (yol, FileMode.APPEND, FileAccess.Write, FileShare.Read); çünkü başlangıçta eski günlükleri silmek istemiyorum ve program çalışırken günlük dosyasını açabilmek istiyorum.
John

1
Bu, mevcut tüm aramalarımı değiştirmemi gerektirmedi Console.WriteLine(), tam olarak istediğim buydu.
x6herbius

Sallanan herkes için bunun bunu nasıl yaptığı kafası karışık. Arayın Console.SetOut(doubleWriter);. Konsol için globalde değişiklik yapmak biraz zaman aldı, çünkü pratikte hiçbir şeyin global olmadığı uygulamalarda çalışmaya çok alıştım. İyi şeyler!
Douglas Gaskell

13

Log4net'e göz atın . Log4net ile tek bir günlük ifadesiyle her iki yere de günlük mesajları gönderebilecek konsol ve dosya ekleyicileri kurabilirsiniz.


6
Zaten orada olanlarla yapılabiliyorsa fazladan kitaplardan kaçınılması gerektiğini düşünüyorum.
Oliver Friedrich

Ayrıca log4net'i tavsiye ediyorum, ancak görünüşe göre NLog toplulukta yerini alıyor.
Mark Richman

10

>Komutu kullanarak çıktıyı bir dosyaya yönlendiremez misiniz ?

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

Yansıtmanız gerekirse tee, çıktıyı bir dosyaya bölen bir win32 sürümünü bulmayı deneyebilirsiniz .

PowerShell'den tee çalıştırmak için /superuser/74127/tee-for-windows adresine bakın


8
Aynaya ihtiyacım var. Bu yüzden konu ve vücutta bahsediliyor. Yine de ipucu için teşekkürler :)
xyz

8

TextWriter sınıfını alt sınıflara ayırabilir ve daha sonra örneğini Console.Out'a Console.SetOut yöntemini kullanarak atayabilirsiniz - bu, özellikle aynı dizeyi günlük yönteminde her iki yönteme de iletmekle aynı şeyi yapar.

Başka bir yol, kendi Console sınıfınızı bildirebilir ve sınıfları ayırt etmek için using ifadesini kullanabilir:

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

Standart konsola erişmek için şunlara ihtiyacınız vardır:

global::Console.Whatever

8

DÜZENLEME: Bu yöntem, üçüncü taraf paketinden gelen konsol bilgilerinin yeniden yönlendirilmesine olanak sağlar. WriteLine yöntemini geçersiz kılmak benim durumum için iyidir, ancak üçüncü taraf paketine bağlı olarak diğer Yazma yöntemlerini geçersiz kılmanız gerekebilir.

İlk olarak StreamWriter'dan doğal olarak yeni bir sınıf oluşturmamız gerekiyor, örneğin CombinedWriter;

Ardından Console.Out ile yeni bir CombinedWriter hazırlayın;

Son olarak, Console.SetOut ile konsol çıktısını yeni sınıfın anına yönlendirebiliriz;

Aşağıdaki kod yeni sınıf benim için çalışıyor.

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

Bu şekilde konsolda görüntülenen hiçbir şeyi kaçırmayacağız.
Düşünmeye Devam Et

1
Aşağıdaki yöntemleri geçersiz kılmak gerekir public override void Write(char value);, public override void Write(char[] buffer);, public override void Write(string value);ve public override void Write(char[] buffer, int index, int count);. Aksi takdirde, WriteLine(format, ...)yöntemi kullanırsanız konsola yazdırmaz .
Dmytro Ovdiienko

6

Log4net bunu sizin için yapabilir. Sadece şöyle bir şey yazarsın:

logger.info("Message");

Yapılandırma, çıktının konsola mı, dosyaya mı yoksa her ikisine birden mi gideceğini belirleyecektir.


5

Bence zaten kullanmakta olduğunuz şey en iyi yaklaşım. Çıktınızı esasen yansıtmak için basit bir yöntem.

İlk önce başlangıçta global bir TextWriter bildirin:

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

Ardından yazmak için bir yöntem yapın:

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

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

Şimdi kullanmak yerine Console.WriteLine("...");kullanın Log("...");. Bu kadar basit. Daha da kısa!


İmleç pozisyonunu ( Console.SetCursorPosition(x, y);) kaydırırsanız bazı sorunlar olabilir , ancak aksi takdirde iyi çalışır, ben de kullanırım!

DÜZENLE

Tabii ki, Console.Write();sadece WriteLines kullanmıyorsanız, aynı şekilde bir yöntem oluşturabilirsiniz .


1
Bu en basit çözümdür. Bunu programınızın sonuna eklemeyi unutmayın: <br/> txtMirror.Flush (); txtMirror.Close ();
Dominic Isaia

3

Arul tarafından önerildiği Console.SetOutgibi kullanımı, çıktıyı bir metin dosyasına yeniden yönlendirmek için kullanılabilir:

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

2

StreamWriter'dan miras alınan bir sınıfı kullanma kararı, kullanıcının önerileri Keep Thinking, işe yarar. Ama yapıcı tabanına eklemem gerekiyordu.AutoFlush = true:

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

ve yıkıcıya açık bir çağrı:

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

Aksi takdirde, dosya tüm verileri kaydettiğinden daha önce kapatılır.

Bunu şu şekilde kullanıyorum:

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

2

Mükemmel çözüm için Düşünmeye Devam Et'e teşekkür ederiz! Yalnızca konsol ekranı için beklenen (amaçlarım için) belirli konsol yazma olaylarını günlüğe kaydetmekten kaçınmak için bazı geçersiz kılmalar ekledim.

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

Dispose yöntemini değiştirip ardından base.Dispose () 'u çağırmanızın belirli bir nedeni var mı?
Adam Plocher

1

Kontrol etmediğiniz bir koddan, örneğin üçüncü taraf kitaplıktan konsol çıktısını çoğaltırsanız, tüm TextWriter üyelerinin üzerine yazılmalıdır. Kod, bu başlıktaki fikirleri kullanır.

Kullanım:

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

ConsoleMirroring sınıfı

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

TextWriter'dan miras alınan kendi sınıfınızı uygulayarak ve WriteLine yöntemini geçersiz kılarak, Console.Out to Trace'in şeffaf bir yansımasını gerçekten oluşturabilirsiniz.

WriteLine'da bunu Trace'e yazabilir ve daha sonra dosyaya yazacak şekilde yapılandırılabilir.

Bu yanıtı çok yararlı buldum: https://stackoverflow.com/a/10918320/379132

Aslında benim için çalıştı!


0

Cevabım en çok oy alan kabul edilmeyen cevaba ve aynı zamanda şimdiye kadarki en zarif çözüm olduğunu düşündüğüm en az oy alan cevaba dayanıyor . Kullanabileceğiniz akış türü açısından biraz daha geneldir ( MemoryStreamörneğin bir kullanabilirsiniz ), ancak kısalık için ikinci yanıtta bulunan tüm genişletilmiş işlevleri atladım.

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

Kullanım:

using (var stream = File.Create(Path.Combine(Path.GetTempPath(), AppDomain.CurrentDomain.FriendlyName)))
using (var writer = new ConsoleMirrorWriter(stream))
{
    // Code using console output.
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.