Как сохранить вывод консольного приложения - PullRequest
10 голосов
/ 14 сентября 2008

Мне нужен совет о том, как сделать так, чтобы мое консольное приложение C # отображало текст для пользователя через стандартный вывод, при этом в дальнейшем он был доступен. Фактическая функция, которую я хотел бы реализовать, - это сбросить весь выходной буфер в текстовый файл в конце выполнения программы.

Обходной путь, который я использую, пока не нахожу более чистого подхода, состоит в том, чтобы подкласс TextWriter переопределяет методы записи, чтобы они одновременно записывали в файл и вызывали исходный модуль записи stdout. Примерно так:

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

Убедитесь, что он все время пишет и сбрасывает файл. Я хотел бы сделать это только в конце выполнения, но я не мог найти способ получить доступ к выходному буферу.

Также, извините за неточности с указанным кодом (пришлось написать его ad hoc , извините;).

Ответы [ 6 ]

5 голосов
/ 14 сентября 2008

Идеальным решением для этого является использование log4net с консольным приложением и файловым приложением. Также доступно много других приложений. Это также позволяет вам включать и выключать различные приложения во время выполнения.

4 голосов
/ 14 сентября 2008

Не думаю, что с вашим подходом что-то не так.

Если вы хотели повторно использовать код, рассмотрите возможность реализации класса с именем MultiWriter или некоторого такого, который принимает в качестве входных данных два (или N?) TextWriter потока и распределяет все записи, сбросы и т. Д. В эти потоки. Затем вы можете сделать это с помощью файла / консоли, но так же легко вы можете разделить любой выходной поток. Полезно!

1 голос
/ 14 сентября 2008

Я бы сказал, имитировать диагностику, которую использует сам .NET (Trace and Debug).

Создайте «выходной» класс, который может иметь разные классы, соответствующие интерфейсу текстового вывода. Вы отправляете отчет в выходной класс, он автоматически отправляет выходные данные заданным классам (ConsoleOutput, TextFileOutput, Wh whatOutput) .. И т. Д. Это также оставляет вас открытым для добавления других «выходных» типов (таких как xml / xslt, чтобы получить красиво отформатированный отчет?).

Посмотрите коллекцию Trace Listeners , чтобы понять, что я имею в виду.

1 голос
/ 14 сентября 2008

Вероятно, не то, что вы хотите, но на всякий случай ... Очевидно, PowerShell реализует версию почтенной команды tee. Который в значительной степени предназначен именно для этой цели. Так что ... курите их, если у вас есть.

0 голосов
/ 15 декабря 2008

Я работаю над реализацией аналогичной функции для захвата вывода, отправленного на консоль, и сохранения его в журнале, в то же время передавая вывод в режиме реального времени на обычную консоль, чтобы она не ломала приложение (например, если оно консольное приложение!).

Если вы все еще пытаетесь сделать это в своем собственном коде, сохраняя вывод консоли (в отличие от использования системы ведения журнала для сохранения только той информации, которая вам действительно нужна), я думаю, что вы можете избежать сброса после каждой записи , если вы также переопределите Flush () и убедитесь, что он сбрасывает оригинальный stdoutWriter, который вы сохранили, а также ваш fileWriter. Это необходимо сделать в случае, если приложение пытается сбросить частичную строку в консоль для немедленного отображения (например, запроса ввода, индикатора выполнения и т. Д.), Чтобы переопределить обычную буферизацию строки.

Если при таком подходе возникают проблемы с буферизацией вывода консоли, вам может потребоваться убедиться, что WriteLine () сбрасывает stdoutWriter (но, вероятно, не нужно сбрасывать fileWriter, за исключением случаев, когда ваш Flush () переопределяет называется). Но я бы подумал, что оригинальный Console.Out (на самом деле идущий в консоль) автоматически сбросит свой буфер на новую строку, поэтому вам не нужно его форсировать.

Возможно, вы также захотите переопределить Close (), чтобы (сбросить и) закрыть ваш fileWriter (и, вероятно, stdoutWriter также), но я не уверен, действительно ли это необходимо или если Close () в base TextWriter выдаст Flush () (который вы уже переопределите), и вы можете рассчитывать на выход из приложения, чтобы закрыть файл. Вы должны, вероятно, проверить, что он сбрасывается при выходе, чтобы быть уверенным. И имейте в виду, что неправильный выход (сбой), скорее всего, не сбрасывает буферизованный вывод. Если это проблема, то может потребоваться очистка fileWriter на новой строке, но это еще одна хитрая червь, с которым нужно разобраться.

0 голосов
/ 14 сентября 2008

Рассмотрите возможность рефакторинга вашего приложения, чтобы отделить части взаимодействия с пользователем от бизнес-логики. По моему опыту, такое разделение весьма полезно для структуры вашей программы.

Для конкретной проблемы, которую вы пытаетесь решить, для части, взаимодействующей с пользователем, становится простым изменить свое поведение с Console.WriteLine на файловый ввод / вывод.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...