ในแอปพลิเคชันคอนโซล C # มีวิธีที่ชาญฉลาดในการมิเรอร์เอาต์พุตคอนโซลเป็นไฟล์ข้อความหรือไม่?
ขณะนี้ฉันเพิ่งส่งสตริงเดียวกันไปยังทั้งสองConsole.WriteLine
และInstanceOfStreamWriter.WriteLine
ในวิธีการบันทึก
ในแอปพลิเคชันคอนโซล C # มีวิธีที่ชาญฉลาดในการมิเรอร์เอาต์พุตคอนโซลเป็นไฟล์ข้อความหรือไม่?
ขณะนี้ฉันเพิ่งส่งสตริงเดียวกันไปยังทั้งสองConsole.WriteLine
และInstanceOfStreamWriter.WriteLine
ในวิธีการบันทึก
คำตอบ:
นี่อาจจะเป็นงานมากกว่า แต่ฉันจะไปอีกทางหนึ่ง
สร้างอินสแตนซ์ a 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.");
}
เท่าที่ฉันจำได้คุณสามารถกำหนด Listeners ในการกำหนดค่าแอปพลิเคชันทำให้สามารถเปิดใช้งานหรือปิดใช้งานการบันทึกได้โดยไม่ต้องสัมผัสโครงสร้าง
นี่เป็นคลาสง่ายๆที่คลาสย่อย TextWriter อนุญาตให้เปลี่ยนทิศทางของอินพุตไปยังไฟล์และคอนโซล
ใช้แบบนี้ครับ
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;
}
}
}
Console.WriteLine()
ซึ่งเป็นสิ่งที่ฉันต้องการ
Console.SetOut(doubleWriter);
มองหา ซึ่งกำลังปรับเปลี่ยน global สำหรับ Console ฉันต้องใช้เวลาสักหน่อยเนื่องจากฉันคุ้นเคยกับการทำงานในแอปพลิเคชันที่แทบไม่มีอะไรเป็นสากล สิ่งที่ดี!
คุณไม่สามารถเปลี่ยนเส้นทางผลลัพธ์ไปยังไฟล์โดยใช้>
คำสั่งได้หรือไม่?
c:\>Console.exe > c:/temp/output.txt
หากคุณต้องการมิเรอร์คุณสามารถลองค้นหาเวอร์ชัน win32 tee
ที่แยกเอาต์พุตเป็นไฟล์
ดู/superuser/74127/tee-for-windowsเพื่อเรียกใช้ทีจาก PowerShell
คุณสามารถซับคลาสคลาส TextWriter จากนั้นกำหนดอินสแตนซ์ให้กับ Console.Out โดยใช้เมธอดConsole.SetOutซึ่งโดยเฉพาะจะทำสิ่งเดียวกันกับการส่งสตริงเดียวกันไปยังทั้งสองวิธีในเมธอดบันทึก
อีกวิธีหนึ่งอาจประกาศคลาสคอนโซลของคุณเองและใช้คำสั่งใช้เพื่อแยกความแตกต่างระหว่างคลาส:
using Console = My.Very.Own.Little.Console;
ในการเข้าถึงคอนโซลมาตรฐานคุณจะต้อง:
global::Console.Whatever
แก้ไข: วิธีนี้ให้ความเป็นไปได้ในการเปลี่ยนเส้นทางข้อมูลคอนโซลที่มาจากแพ็คเกจของบุคคลที่สาม การแทนที่วิธี WriteLine นั้นดีสำหรับสถานการณ์ของฉัน แต่คุณอาจต้องแทนที่วิธีการเขียนอื่น ๆ ขึ้นอยู่กับแพ็คเกจของบุคคลที่สาม
ก่อนอื่นเราต้องสร้างคลาสใหม่จาก StreamWriter กล่าว CombinedWriter;
จากนั้นเริ่มต้น CombinedWriter ทันทีใหม่ด้วย Console.Out;
ในที่สุดเราสามารถเปลี่ยนทิศทางเอาต์พุตคอนโซลไปยังทันทีของคลาสใหม่โดย 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);
}
}
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, ...)
วิธีการ
Log4netสามารถทำสิ่งนี้ให้คุณได้ คุณจะเขียนเฉพาะสิ่งนี้:
logger.info("Message");
การกำหนดค่าจะกำหนดว่างานพิมพ์จะไปที่คอนโซลไฟล์หรือทั้งสองอย่าง
ฉันคิดว่าสิ่งที่คุณใช้อยู่เป็นแนวทางที่ดีที่สุด วิธีง่ายๆในการสะท้อนผลลัพธ์ของคุณเป็นหลัก
ก่อนอื่นให้ประกาศ 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
ตามที่ Arul แนะนำการใช้Console.SetOut
สามารถใช้เพื่อเปลี่ยนทิศทางเอาต์พุตไปยังไฟล์ข้อความ:
Console.SetOut(new StreamWriter("Output.txt"));
การตัดสินใจใช้คลาสที่สืบทอดมาจาก StreamWriter คำแนะนำโดยผู้ใช้ Keep Thinking ใช้ได้ผล แต่ฉันต้องเพิ่มลงในฐานตัวสร้าง AutoFlush = true:
{
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);
ขอขอบคุณ Keep Thinking สำหรับวิธีแก้ปัญหาที่ยอดเยี่ยม! ฉันได้เพิ่มการแทนที่เพิ่มเติมเพื่อหลีกเลี่ยงการบันทึกเหตุการณ์การเขียนคอนโซลบางอย่างที่คาดว่า (สำหรับวัตถุประสงค์ของฉัน) สำหรับการแสดงผลคอนโซลเท่านั้น
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();
}
}
}
หากคุณทำซ้ำคอนโซลเอาต์พุตจากรหัสที่คุณไม่ได้ควบคุมตัวอย่างเช่นไลบรารีของบุคคลที่สามสมาชิกทั้งหมดของ 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);
}
}
}
คุณสามารถสร้างคอนโซลมิเรอร์แบบโปร่งใสได้จริง ๆ ออกไปที่การติดตามโดยใช้คลาสของคุณเองที่สืบทอดมาจาก TextWriter และแทนที่เมธอด WriteLine
ใน WriteLine คุณสามารถเขียนลงใน Trace ซึ่งสามารถกำหนดค่าให้เขียนลงไฟล์ได้
ฉันพบว่าคำตอบนี้มีประโยชน์มาก: https://stackoverflow.com/a/10918320/379132
มันใช้งานได้จริงสำหรับฉัน!
คำตอบของฉันมาจากคำตอบที่ไม่ได้รับการโหวตมากที่สุดและยังเป็นคำตอบที่ได้รับการโหวตน้อยที่สุดซึ่งฉันคิดว่าเป็นคำตอบที่ดีที่สุด เป็นเพียงเล็กน้อยทั่วไปในแง่ของประเภทสตรีมที่คุณสามารถใช้ได้ (คุณอาจใช้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.
}