Pergunta

Preciso de conselhos sobre como fazer com que meu aplicativo de console C# exiba texto para o usuário por meio da saída padrão e ainda possa acessá-lo posteriormente.O recurso real que eu gostaria de implementar é despejar todo o buffer de saída em um arquivo de texto no final da execução do programa.

A solução alternativa que uso enquanto não encontro uma abordagem mais limpa é subclassificar TextWriter substituindo os métodos de gravação para que ambos gravem em um arquivo e chamem o gravador stdout original.Algo assim:

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

Veja se ele grava e libera o arquivo o tempo todo.Adoraria fazer isso apenas no final da execução, mas não consegui encontrar nenhuma forma de acessar o buffer de saída.

Além disso, desculpe as imprecisões com o código acima (tive que escrevê-lo Ad hoc, desculpe ;).

Foi útil?

Solução

A solução perfeita para isso é usar log4net com um anexador de console e um anexador de arquivo.Existem muitos outros anexadores disponíveis também.Ele também permite que você desligue e ligue os diferentes anexadores em tempo de execução.

Outras dicas

Não creio que haja algo de errado com sua abordagem.

Se você quiser um código reutilizável, considere implementar uma classe chamada MultiWriter ou algo assim que receba como entrada dois (ou N?) TextWriter transmite e distribui todos os mandados, liberações, etc.para esses fluxos.Então você pode fazer essa coisa de arquivo/console, mas com a mesma facilidade você pode dividir qualquer fluxo de saída.Útil!

Provavelmente não é o que você quer, mas apenas no caso ...Aparentemente, Implementos do PowerShell uma versão do venerável tee comando.Que se destina exatamente a esse propósito.Então...fume-os se você os tiver.

Eu diria que imita os diagnósticos que o próprio .NET usa (Trace e Debug).

Crie uma classe de "saída" que possa ter diferentes classes que aderem a uma interface de saída de texto.Você se reporta à classe de saída, ela envia automaticamente a saída dada às classes que você adicionou (ConsoleOutput, TextFileOutput, AnythingOutput).E assim por diante..Isso também deixa você aberto para adicionar outros tipos de "saída" (como xml/xslt para obter um relatório bem formatado?).

Confira a Coleção de ouvintes de rastreamento para ver o que quero dizer.

Considere refatorar seu aplicativo para separar as partes de interação do usuário da lógica de negócios.Na minha experiência, tal separação é bastante benéfica para a estrutura do seu programa.

Para o problema específico que você está tentando resolver aqui, torna-se simples para a parte de interação com o usuário alterar seu comportamento de Console.WriteLine para arquivar E/S.

Estou trabalhando na implementação de um recurso semelhante para capturar a saída enviada ao Console e salvá-la em um log enquanto ainda passo a saída em tempo real para o Console normal, para que não interrompa o aplicativo (por exemplo.se for um aplicativo de console!).

Se você ainda está tentando fazer isso em seu próprio código salvando a saída do console (em vez de usar um sistema de registro para salvar apenas as informações que realmente lhe interessam), acho que você pode evitar a liberação após cada gravação, desde como você também substitui Flush() e certifique-se de liberar o original stdoutWriter você salvou, assim como seu fileWriter.Você deseja fazer isso caso o aplicativo esteja tentando liberar uma linha parcial no console para exibição imediata (como um prompt de entrada, um indicador de progresso, etc.), para substituir o buffer de linha normal.

Se essa abordagem tiver problemas com a saída do console sendo armazenada em buffer por muito tempo, talvez seja necessário certificar-se de que WriteLine() seja liberado stdoutWriter (mas provavelmente não precisa liberar fileWriter exceto quando sua substituição Flush() é chamada).Mas eu acho que o original Console.Out (na verdade, indo para o console) liberaria automaticamente seu buffer em uma nova linha, então você não deveria forçá-lo.

Você também pode substituir Close() para (liberar e) fechar seu fileWriter (e provavelmente stdoutWriter também), mas não tenho certeza se isso é realmente necessário ou se um Close() no TextWriter base emitiria um Flush() (que você já substituiria) e você pode confiar na saída do aplicativo para fechar seu arquivo.Você provavelmente deve testar se ele é liberado na saída, para ter certeza.E esteja ciente de que uma saída anormal (travamento) provavelmente não liberará a saída em buffer.Se isso for um problema, enxágue fileWriter na nova linha pode ser desejável, mas essa é outra lata de vermes complicada de resolver.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top