11

我需要有关如何让我的 C# 控制台应用程序通过标准输出向用户显示文本同时仍然能够在以后访问它的建议。我想实现的实际功能是在程序执行结束时将整个输出缓冲区转储到文本文件中。

当我没有找到更简洁的方法时,我使用的解决方法是子类化TextWriter重写写入方法,这样它们既可以写入文件,又可以调用原始的标准输出编写器。像这样的东西:

public class DirtyWorkaround {
  private class DirtyWriter : TextWriter {
    private TextWriter stdoutWriter;
    private StreamWriter fileWriter;

    public DirtyWriter(string path, TextWriter stdoutWriter) {
      this.stdoutWriter = stdoutWriter;
      this.fileWriter = new StreamWriter(path);
    }

    override public void Write(string s) {
      stdoutWriter.Write(s);

      fileWriter.Write(s);
      fileWriter.Flush();
    }

    // Same as above for WriteLine() and WriteLine(string),
    // plus whatever methods I need to override to inherit
    // from TextWriter (Encoding.Get I guess).
  }

  public static void Main(string[] args) {
    using (DirtyWriter dw = new DirtyWriter("path", Console.Out)) {
      Console.SetOut(dw);

      // Teh codez
    }
  }
}

看到它一直在写入和刷新文件。我只想在执行结束时这样做,但我找不到任何访问输出缓冲区的方法。

另外,请原谅上述代码的不准确之处(必须临时编写,抱歉;)。

4

6 回答 6

6

完美的解决方案是将log4net与控制台附加程序和文件附加程序一起使用。还有许多其他可用的附加程序。它还允许您在运行时关闭和打开不同的附加程序。

于 2008-09-14T04:45:42.800 回答
5

我不认为你的方法有什么问题。

如果您想要可重用的代码,请考虑实现一个名为MultiWriter或类似的类,该类将两个(或 N 个?)TextWriter流作为输入并将所有命令、刷新等分发到这些流。然后你可以做这个文件/控制台的事情,但是你可以很容易地分割任何输出流。有用!

于 2008-09-14T04:06:46.090 回答
1

可能不是您想要的,但以防万一……显然,PowerShell 实现tee了古老命令的一个版本。这几乎就是为了这个目的。所以......如果你有他们,就抽他们。

于 2008-09-14T04:12:43.923 回答
1

我想说模仿 .NET 本身使用的诊断程序(跟踪和调试)。

创建一个“输出”类,它可以有不同的类来遵守文本输出接口。您向输出类报告,它会自动将给定的输出发送给您添加的类(ConsoleOutput、TextFileOutput、WhateverOutput)。等等。这也让您可以添加其他“输出”类型(例如 xml/ xslt 以获得格式良好的报告?)。

查看Trace Listeners Collection以了解我的意思。

于 2008-09-14T06:22:47.810 回答
0

考虑重构您的应用程序以将用户交互部分与业务逻辑分开。根据我的经验,这种分离对您的程序结构非常有益。

对于您在此处尝试解决的特定问题,用户交互部分可以直接将其行为从文件 I/O 更改Console.WriteLine为文件 I/O。

于 2008-09-14T06:39:13.200 回答
0

我正在实现一个类似的功能来捕获发送到控制台的输出并将其保存到日志中,同时仍将输出实时传递到普通控制台,这样它就不会破坏应用程序(例如,如果它是一个控制台应用程序!)。

如果您仍在尝试通过保存控制台输出在自己的代码中执行此操作(而不是使用日志系统来仅保存您真正关心的信息),我认为您可以避免每次写入后刷新,只要因为您还覆盖了 Flush() 并确保它刷新stdoutWriter您保存的原始文件以及fileWriter. 如果应用程序试图将部分行刷新到控制台以立即显示(例如输入提示、进度指示器等),您希望这样做,以覆盖正常的行缓冲。

如果该方法存在控制台输出缓冲时间过长的问题,则可能需要确保 WriteLine() 刷新stdoutWriter(但可能不需要刷新,fileWriter除非调用 Flush() 覆盖)。但我认为原来的Console.Out(实际上是进入控制台)会在换行符上自动刷新它的缓冲区,所以你不应该强迫它。

您可能还想覆盖 Close() 以(刷新和)关闭您的fileWriter(可能stdoutWriter也是如此),但我不确定这是否真的需要,或者基础 TextWriter 中的 Close() 是否会发出 Flush() (您已经覆盖)并且您可能依赖应用程序退出来关闭您的文件。可以肯定的是,您可能应该测试它是否在退出时被刷新。请注意,异常退出(崩溃)可能不会刷新缓冲输出。如果这是一个问题,fileWriter在换行符上刷新可能是可取的,但这是另一个棘手的蠕虫问题。

于 2008-12-15T18:21:02.290 回答