如何在 C# 中同时将控制台输出到多个流?

问题描述 投票:0回答:4

我有一个程序可以获取控制台输出并将其写入日志文件,但它不再显示在控制台窗口中。有没有办法将其保留在窗口中,但也将其写入日志文件?

更新:

appLogStream = new FileStream(logFile, FileMode.Append, FileAccess.Write, FileShare.Read);
TextWriter logtxtWriter = Console.Out;
logstrmWriter = new StreamWriter(appLogStream);
if(!console) Console.SetOut(logstrmWriter);
logstrmWriter.AutoFlush = true;
Console.WriteLine("Started at " + DateTime.Now);

console 是类中设置的常量。它基本上告诉它是否正在使用控制台窗口(如果不在控制台中,则不会调用 readline 等)。

那么有没有办法同时写入控制台和文件?

c# .net-4.0 stream
4个回答
2
投票

您可以简单地读取该流并将其记录并打印出来。

如果您将输出流分配给输出文件的输入流,这在一定程度上取决于您的代码,如果您将内容读取到应该更容易的缓冲区,这可能会有点困难。


关于您的更新,我建议您将所有

Console
替换为自定义日志记录功能,例如MyLogger 的实例(代码如下)。它将您的输出写入控制台和日志文件。

class MyLogger {
    private FileStream appLogStream;

    public MyLogger() {
        appLogStream = new FileStream(logFile, FileMode.Append, FileAccess.Write,
                                      FileShare.Read);
        appLogStream.WriteLine("Started at " + DateTime.Now);
    }

    public Write(string msg) {
        Console.Write(msg);
        appLogStream.Write(msg);
    }

    public WriteLine(string msg) {
        Console.WriteLine(msg);
        appLogStream.WriteLine(msg);
    }
}

2
投票

我认为你可以做这样的事情:

 public class ConsoleDecorator : TextWriter
{
    private TextWriter m_OriginalConsoleStream;

    public ConsoleDecorator(TextWriter consoleTextWriter)
    {
        m_OriginalConsoleStream = consoleTextWriter;
    }

    public override void WriteLine(string value)
    {
        m_OriginalConsoleStream.WriteLine(value);

        // Fire event here with value
    }


    public static void SetToConsole()
    {
        Console.SetOut(new ConsoleDecorator(Console.Out));
    }
}

您必须通过调用 ConsoleDecorator.SetToConsole() 来“注册”包装器; 之后,每个 Console.WriteLine 调用都将访问自定义方法,您可以在其中触发事件并获取在其他位置写入的文本(例如日志记录)。

如果您想使用这种方式,则必须使该类成为单例,然后您可以从其他类访问偶数注册(应该在触发偶数时写入日志文件)


0
投票

当您调用 Console.SetOut 时,您指定 Console 应写入的位置。如果您不这样做(即通常使用 Console 的方式),并且您调用 Console.Write,它会检查它是否有输出编写器,如果没有,则将其设置为

   stream = OpenStandardOutput(256);

然后

        Encoding encoding = Encoding.GetEncoding((int) Win32Native.GetConsoleOutputCP());
        writer = TextWriter.Synchronized(new StreamWriter(stream, encoding, 256, false) { HaveWrittenPreamble = true, AutoFlush = true });

所以你应该能够做你现在正在做的事情,如果你还想将所有内容回显到标准输出,就像你没有重定向控制台一样,你可以使用你自己打开的流来创建你自己的编写器

Console.OpenStandardOutput 
方法。该代码中使用的
Win32Native
是内部的,因此您无权访问它,但您可以使用
Console.OutputEncoding
检索它正在使用的编码。

您还可以尝试使用

Console.Out
属性在调用 SetOut 之前获取并挂载到标准输出 TextWriter。然后您可以使用它来回显到标准输出。


0
投票

最后我就这样离开了课堂:

public class ConsoleDecorator : TextWriter
{
    private TextWriter m_OriginalConsoleStream;

    public override Encoding Encoding => m_OriginalConsoleStream.Encoding;

    public ConsoleDecorator(TextWriter consoleTextWriter)
    {
        m_OriginalConsoleStream = consoleTextWriter;
    }

    public override void WriteLine(string value)
    {
        string cHora = DateTime.Now.ToString("yyyyMMddTHHmm:ss") + "." + DateTime.Now.Millisecond.ToString().PadLeft(3, '0');
        string msg = $"{cHora}: {value}";
        m_OriginalConsoleStream.WriteLine(msg);

        // Fire event here with value
        if (Properties.Settings.Default.GenerateLog)
        {
            // Ruta y nombre del archivo de texto
            string filePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "APP_" + DateTime.Now.ToString("yyyyMMdd").Substring(2, 6) + ".Log");
            try
            {
                using (StreamWriter writer = new StreamWriter(filePath, true))
                {
                    writer.Write('\n' + msg);
                }
            }
            catch { }
        }
    }

    public static void SetToConsole()
    {
        Console.SetOut(new ConsoleDecorator(Console.Out));
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.