कंसोल आउटपुट को किसी फ़ाइल में मिरर करना


88

C # कंसोल एप्लिकेशन में, टेक्स्ट आउटपुट को टेक्स्ट फ़ाइल में प्रदर्शित करने का स्मार्ट तरीका है?

वर्तमान में मैं एक ही स्ट्रिंग को दोनों में Console.WriteLineऔर InstanceOfStreamWriter.WriteLineएक लॉग विधि में पारित कर रहा हूं ।

जवाबों:


117

यह किसी और तरह का काम हो सकता है, लेकिन मैं दूसरे रास्ते पर जाऊंगा।

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

जहां तक ​​मैं याद कर सकता हूं, आप एप्लिकेशन कॉन्फ़िगरेशन में श्रोताओं को परिभाषित कर सकते हैं कि बिल्ड को छूने के बिना लॉगिंग को सक्रिय या निष्क्रिय करना संभव है।


4
यह एकदम सही है - धन्यवाद। मुझे Log4Net के बारे में पता था लेकिन ऐसा कुछ के लिए लाइब्रेरी में खींचना गलत लगता है।
xyz

3
मुझे नहीं पता कि वे ट्रेस का एक बड़ा सौदा क्यों नहीं करते हैं - मुझे ऐसा लगता है कि इसे उत्पादन-स्केल लॉगिंग के लिए अच्छी तरह से काम करना चाहिए, लेकिन हर कोई इसे करने के लिए एक अतिरिक्त पुस्तकालय (जैसे log4net) पर निपटना चाहता है।
कोडर

यह वन-वे मिररिंग है। मेरा मतलब है कि यदि आपके पास एक इंटरैक्टिव कंसोल है और उपयोगकर्ता से कुछ डेटा प्राप्त करता है और एक फाइल में सब कुछ लॉग इन करना चाहता है तो यह समाधान काम नहीं करता है। इस साधारण तथ्य के बावजूद मेरा प्रश्न बंद है। यहाँ: stackoverflow.com/questions/3886895/…
Xaqron

6
मुझे वास्तव में यह समाधान पसंद आया, इसलिए मैंने इसके बारे में एक त्वरित ब्लॉग बनाया जिसमें कुछ मामूली सफाई और रास्ते में कुछ स्नैग्स का चलना था। mcrook.com/2014/11/quick-and-easy-console-logging-trace.html महान समाधान के लिए धन्यवाद :)
माइकल क्रुक

51

यह एक साधारण वर्ग है जो टेक्स्टविरिटर को उपविभाजित करता है ताकि इनपुट को फ़ाइल और कंसोल दोनों पर पुनर्निर्देशित किया जा सके।

इसे इस तरह इस्तेमाल करें

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

यहाँ वर्ग है:

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
मुझे लगता है कि यह सबसे पूर्ण समाधान है। राइट / राइटलाइन विधियों के सभी अधिभार को ओवरराइड करने की आवश्यकता नहीं है और अन्य कोड के लिए पारदर्शी है। तो अन्य कोड में कोई बदलाव किए बिना, सभी कंसोल गतिविधि को फ़ाइल में डुप्लिकेट किया जाएगा।
पापड़ी

3
धन्यवाद दोस्त! यह विस्मयकारी है! मैंने अभी File.Create को File.Open (path, FileMode.Append, FileAccess.Write, FileShare.Read) से बदल दिया है; क्योंकि मैं स्टार्टअप पर पुराने लॉग को मिटाना नहीं चाहता हूं और मैं लॉग फ़ाइल को खोलने में सक्षम होना चाहता हूं, जबकि प्रोग्राम अभी भी चल रहा है।
जॉन

1
इसके लिए मुझे अपने सभी मौजूदा कॉल को बदलने की आवश्यकता नहीं थी Console.WriteLine(), जो कि वास्तव में मैं चाहता था।
x6herbius

किसी के द्वारा झूलते हुए कि यह कैसे होता है। के लिए देखो Console.SetOut(doubleWriter);। जो कंसोल के लिए एक वैश्विक संशोधन कर रहा है, यह मुझे थोड़ा सा लगा, क्योंकि मैं उन अनुप्रयोगों में काम करने के लिए अभ्यस्त हूं जहां व्यावहारिक रूप से कुछ भी वैश्विक नहीं है। अच्छी चीज़!
डगलस गास्केल

13

Log4net की जाँच करें । Log4net के साथ आप कंसोल और फाइल एपेंडर्स सेट कर सकते हैं जो एक लॉग स्टेटमेंट के साथ दोनों जगहों पर लॉग मैसेज को आउटपुट कर सकते हैं।


6
ठीक है, मुझे लगता है कि अगर पहले से ही वहां है तो अतिरिक्त कामों से बचना चाहिए।
ओलिवर फ्रेडरिक

मैं log4net की भी सलाह देता हूं, लेकिन ऐसा लग रहा है कि NLog समुदाय में अपनी जगह ले रहा है।
मार्क रिचमैन

10

क्या आप केवल >कमांड का उपयोग करके किसी फ़ाइल में आउटपुट को रीडायरेक्ट नहीं कर सकते हैं ?

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

यदि आपको दर्पण की आवश्यकता है, तो आप एक win32 संस्करण ढूंढ सकते हैं tee कि किसी फ़ाइल में आउटपुट को विभाजित करता है।

PowerShell से टी चलाने के लिए /superuser/74127/tee-for-windows देखें


8
मुझे आईना चाहिए। इसलिए विषय और शरीर में इसका उल्लेख है। हालांकि टिप के लिए धन्यवाद :)
xyz

8

आप TextWriter वर्ग उपवर्ग सकता है, और उसके बाद का उपयोग कर Console.Out करने के लिए अपने उदाहरण आवंटित Console.SetOut पद्धति - जो विशेष रूप से लॉग विधि में दोनों विधियों में समान स्ट्रिंग को पारित करने के समान है।

एक और तरीका हो सकता है कि आप अपनी खुद की कंसोल क्लास घोषित करें और कक्षाओं के बीच अंतर करने के लिए स्टेटमेंट का उपयोग करें:

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

मानक कंसोल तक पहुँचने के लिए आपको तब आवश्यकता होगी:

global::Console.Whatever

8

EDIT: यह विधि कंसोल सूचना को तीसरे पक्ष के पैकेज से आने वाली जानकारी को पुनर्निर्देशित करने की संभावना प्रदान करती है। राइटलाइन विधि को ओवरराइड करना मेरी स्थिति के लिए अच्छा है, लेकिन आपको अन्य लिखने के तरीकों को ओवरराइड करने की आवश्यकता हो सकती है यह तीसरे पक्ष के पैकेज पर निर्भर करता है।

पहले हमें StreamWriter से अंतर्निहित नई कक्षा बनाने की आवश्यकता है, जो CombinedWriter कहते हैं;

फिर Console.Out के साथ CombinedWriter का एक नया इंस्टेंट init;

अंत में हम Console.SetOut द्वारा नए वर्ग के तत्काल में कंसोल आउटपुट को रीडायरेक्ट कर सकते हैं;

निम्नलिखित कोड मेरे लिए नया वर्ग कार्य है।

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

इस तरह हम कंसोल में प्रदर्शित कुछ भी याद नहीं करेंगे।
सोचते रहें

1
आप निम्न विधियों ओवरराइड करना चाहिए public override void Write(char value);, public override void Write(char[] buffer);, public override void Write(string value);और public override void Write(char[] buffer, int index, int count);। अन्यथा यदि आप WriteLine(format, ...)विधि का उपयोग करते हैं तो यह कंसोल पर प्रिंट नहीं करता है ।
Dmytro Ovdiienko

6

Log4net आपके लिए यह कर सकता है। आप केवल कुछ इस तरह से लिखेंगे:

logger.info("Message");

एक कॉन्फ़िगरेशन यह निर्धारित करेगा कि प्रिंट आउट कंसोल, फ़ाइल या दोनों पर जाएगा।


4

मुझे लगता है कि जो आप पहले से उपयोग कर रहे हैं वह सबसे अच्छा तरीका है। अनिवार्य रूप से अपने आउटपुट को दर्पण करने की एक सरल विधि।

पहले शुरुआत में एक वैश्विक TextWriter घोषित करें:

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

फिर लिखने के लिए एक विधि बनाएं:

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

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

अब, उपयोग करने के बजाय Console.WriteLine("...");, उपयोग करें Log("...");। इतना ही आसान। यह और भी छोटा है!


यदि आप शापपत्र ( Console.SetCursorPosition(x, y);) को स्थानांतरित करते हैं, तो कुछ परेशानी हो सकती है , लेकिन अन्यथा अच्छी तरह से काम करता है, मैं खुद भी इसका उपयोग करता हूं!

संपादित करें

Console.Write();यदि आप केवल WriteLines का उपयोग नहीं कर रहे हैं, तो उसी तरह से एक विधि बना सकते हैं


1
यह सबसे सरल उपाय है। इसे अपने कार्यक्रम के अंत में जोड़ना न भूलें: <br/> txtMirror.Flush (); txtMirror.Close ();
डोमिनिक इसिया

3

अरुल द्वारा सुझाए गए अनुसार, Console.SetOutआउटपुट का उपयोग टेक्स्ट फ़ाइल में रीडायरेक्ट करने के लिए किया जा सकता है:

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

2

एक वर्ग का उपयोग करने का निर्णय, स्ट्रीमवृटर से विरासत में मिला, उपयोगकर्ता द्वारा सुझाव रखें सोच, काम करता है। लेकिन मुझे कंस्ट्रक्टर बेस में जोड़ना था।

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

और विध्वंसक को एक स्पष्ट कॉल:

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

अन्यथा, फ़ाइल सभी डेटा रिकॉर्ड करने से पहले बंद हो जाती है।

मैं इसका उपयोग कर रहा हूं:

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

2

उत्कृष्ट समाधान के लिए सोच रखने के लिए धन्यवाद! मैंने कुछ और ओवरराइड जोड़े हैं ताकि कुछ कंसोल लिखने की घटनाओं से बचा जा सके, जो (मेरे उद्देश्यों के लिए) केवल कंसोल डिस्प्ले के लिए अपेक्षित हैं।

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

किसी विशेष कारण से आप डिस्पोज़ विधि की जगह ले रहे हैं और फिर आधार कॉल कर रहे हैं।
एडम प्लोचर

1

यदि आप किसी ऐसे कोड से कंसोल आउटपुट को डुप्लिकेट करते हैं जिसे आप नियंत्रित नहीं करते हैं, उदाहरण के लिए 3rd पार्टी लाइब्रेरी, TextWriter के सभी सदस्यों को ओवरराइट किया जाना चाहिए। कोड इस थ्रेड से विचारों का उपयोग करता है।

उपयोग:

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

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

वास्तव में आप TextWriter से विरासत में मिली अपनी कक्षा को लागू करके और WriteLine विधि को ओवरराइड करके ट्रेस करने के लिए Console.Out का एक पारदर्शी मिररिंग बना सकते हैं।

राइटलाइन में आप इसे ट्रेस में लिख सकते हैं जिसे तब फाइल में लिखने के लिए कॉन्फ़िगर किया जा सकता है।

मुझे यह उत्तर बहुत मददगार लगा: https://stackoverflow.com/a/10918320/379132

यह वास्तव में मेरे लिए काम किया!


0

मेरा जवाब सबसे अधिक गैर-स्वीकृत उत्तर पर आधारित है , और सबसे कम-मतदान जवाब भी है जो मुझे लगता है कि अब तक का सबसे सुरुचिपूर्ण समाधान है। यह उस धारा प्रकार के संदर्भ में थोड़ा अधिक सामान्य है जिसे आप उपयोग कर सकते हैं (आप MemoryStreamउदाहरण के लिए उपयोग कर सकते हैं ), लेकिन मैंने संक्षिप्तता के लिए बाद वाले उत्तर में शामिल सभी विस्तारित कार्यक्षमता को छोड़ दिया है ।

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

उपयोग:

using (var stream = File.Create(Path.Combine(Path.GetTempPath(), AppDomain.CurrentDomain.FriendlyName)))
using (var writer = new ConsoleMirrorWriter(stream))
{
    // Code using console output.
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.