Мне нужен совет о том, как сделать так, чтобы мое консольное приложение 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
}
}
}
Убедитесь, что он все время записывает и сбрасывает файл. Я бы хотел сделать это только в конце выполнения, но я не мог найти никакого доступа к выходному буферу.
Также прошу прощения за неточности в приведенном выше коде (пришлось написать его для этого случая, извините;).





Не думаю, что в вашем подходе что-то не так.
Если вам нужен код многократного использования, подумайте о реализации класса MultiWriter или другого такого, который принимает в качестве входных данных два (или N?) Потока TextWriter и распределяет все записи, сбросы и т. Затем вы можете сделать этот файл / консоль, но так же легко вы можете разделить любой выходной поток. Полезный!
Наверное, не то, что вы хотите, но на всякий случай ... Судя по всему, PowerShell реализует - это версия маститой команды tee. Что в значительной степени предназначено именно для этой цели. Так что ... курите их, если они у вас есть.
Идеальным решением для этого является использование log4net с консольным приложением и файловым приложением. Также доступно множество других приложений. Это также позволяет вам включать и выключать различные приложения во время выполнения.
Замечательная идея! Действительно, мне нужен регистратор. Таким образом, я могу хранить гораздо больше информации, чем просто показано пользователю (и меньше его беспокоить). Часто лучшее решение исходит из другого подхода, исходящего от кого-то постороннего по отношению к проблеме.
Я думаю, что в этом случае было бы излишним использовать стороннюю библиотеку, когда для добавления необходимой функциональности в систему может потребоваться лишь небольшой объем работы.
Я согласен, что log4net - это довольно тяжелая зависимость.
Это больше похоже на взлом, чем на подход, изложенный в вопросе.
Хороший момент. Я проверю эту стоимость, когда вернусь к работе на этой неделе. Главное преимущество, которое я здесь обнаружил, заключается в том, что легче сохранить отладочную информацию в файле, не выводя ее на экран. Кроме того, последовательный ввод-вывод является основным узким местом в моем проекте.
Как сохранить вывод из powershell.exe? - Я почти уверен, что Windows также не позволит вам перенаправить стандартный ввод / вывод / ошибку через границу безопасности администратора / не администратора. Вам нужно будет найти другой способ получить вывод из программы, запущенной от имени администратора - Ссылка: stackoverflow.com/a/8690661
Я бы сказал, имитируйте диагностику, которую использует сама .NET (трассировка и отладка).
Создайте "выходной" класс, который может иметь разные классы, привязанные к интерфейсу вывода текста. Вы сообщаете выходному классу, он автоматически отправляет выходные данные добавленным вами классам (ConsoleOutput, TextFileOutput, WhateverOutput) .. И так далее .. Это также оставляет вас открытыми для добавления других типов «выходных» (таких как xml / xslt, чтобы получить отчет в красивом формате?).
Посмотрите Коллекция слушателей трассировки, чтобы понять, что я имею в виду.
Рассмотрите возможность рефакторинга вашего приложения, чтобы отделить части взаимодействия с пользователем от бизнес-логики. По моему опыту, такое разделение весьма полезно для структуры вашей программы.
Для конкретной проблемы, которую вы пытаетесь решить здесь, для части взаимодействия с пользователем становится просто изменить свое поведение с Console.WriteLine на файловый ввод-вывод.
Я работаю над реализацией аналогичной функции для захвата вывода, отправляемого в консоль, и сохранения его в журнале, при этом передавая вывод в реальном времени в обычную консоль, чтобы он не нарушал работу приложения (например, если это консольное приложение !).
Если вы все еще пытаетесь сделать это в своем собственном коде, сохраняя вывод консоли (в отличие от использования системы журналов для сохранения только той информации, которая вам действительно важна), я думаю, вы можете избежать сброса после каждой записи, если поскольку вы также переопределяете Flush () и убедитесь, что он сбрасывает исходный stdoutWriter, который вы сохранили, а также ваш fileWriter. Вы хотите сделать это в случае, если приложение пытается сбросить частичную строку на консоль для немедленного отображения (например, приглашения ввода, индикатора выполнения и т. д.), Чтобы переопределить обычную буферизацию строки.
Если при таком подходе возникают проблемы с слишком долгой буферизацией вывода на консоль, вам может потребоваться убедиться, что WriteLine () сбрасывает stdoutWriter (но, вероятно, не нужно сбрасывать fileWriter, кроме случаев, когда вызывается переопределение Flush ()). Но я бы подумал, что исходный Console.Out (фактически идущий на консоль) автоматически сбрасывает свой буфер при переходе на новую строку, поэтому вам не нужно форсировать его.
Вы также можете переопределить Close (), чтобы (очистить и) закрыть свой fileWriter (и, вероятно, stdoutWriter), но я не уверен, действительно ли это необходимо, или если Close () в базовом TextWriter вызовет Flush ( ) (который вы уже переопределите), и вы можете полагаться на выход приложения, чтобы закрыть свой файл. Вы, вероятно, должны проверить, что он сбрасывается при выходе, чтобы быть уверенным. И имейте в виду, что аварийный выход (сбой), скорее всего, не приведет к сбросу буферизованного вывода. Если это проблема, может быть желательно промыть fileWriter на новой строке, но это еще одна хитрая баня червей, которую нужно решить.
Проблема с моим подходом в том, что я держу файл открытым и все время его промываю. И, я полагаю, открытие и закрытие файла при каждой записи было бы обременительным. Однако ваша идея MultiWriter очень умная :)