Как сохранить вывод консольного приложения

StackOverflow https://stackoverflow.com/questions/61110

  •  09-06-2019
  •  | 
  •  

Вопрос

Мне нужен совет о том, как мое консольное приложение 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
    }
  }
}

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

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

Это было полезно?

Решение

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

Другие советы

Я не думаю, что в вашем подходе есть что-то неправильное.

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

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

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

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

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

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

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

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

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top