【问题标题】:How To Split a Single TextWriter into Multiple Outputs in .NET?如何在 .NET 中将单个 TextWriter 拆分为多个输出?
【发布时间】:2012-02-08 01:29:34
【问题描述】:

我从我的 C# 代码中调用一个 API,该 API 有一个带有以下标头的方法

public void ExternalFactory.SetOut(TextWriter outputStream)  

我通常把这个方法称为

ExternalFactory.SetOut(Console.Out) 

让 API 将其所有信息写入控制台。但是,除了写入控制台之外,我还希望将此信息存储在更永久的位置,例如文本文件。

我的第一个猜测是我需要创建某种客户 TextWriter 来拆分流并将一个发送到控制台,一个发送到 StreamWriter。这里的正确方法是什么?

【问题讨论】:

    标签: c# stream io


    【解决方案1】:

    在编译和首次使用后未进行测试,但可能会节省一些打字时间。烦人的已经不存在了。

    /// <summary>
    /// Spreads data out to multiple text writers.
    /// </summary>
    class TextWriterMulti : System.IO.TextWriter
    {
        private System.Collections.Generic.List<System.IO.TextWriter> writers = new System.Collections.Generic.List<System.IO.TextWriter>();
        private System.IFormatProvider formatProvider = null;
        private System.Text.Encoding encoding = null;
    
        #region TextWriter Properties
        public override System.IFormatProvider FormatProvider
        {
            get
            {
                System.IFormatProvider formatProvider = this.formatProvider;
                if (formatProvider == null)
                {
                    formatProvider = base.FormatProvider;
                }
                return formatProvider;
            }
        }
    
        public override string NewLine
        {
            get { return base.NewLine; }
    
            set
            {
                foreach (System.IO.TextWriter writer in this.writers)
                {
                    writer.NewLine = value;
                }
    
                base.NewLine = value;
            }
        }
    
    
        public override System.Text.Encoding Encoding
        {
            get
            {
                System.Text.Encoding encoding = this.encoding;
    
                if (encoding == null)
                {
                    encoding = System.Text.Encoding.Default;
                }
    
                return encoding;
            }
        }
    
        #region TextWriter Property Setters
    
        TextWriterMulti SetFormatProvider(System.IFormatProvider value)
        {
            this.formatProvider = value;
            return this;
        }
    
        TextWriterMulti SetEncoding(System.Text.Encoding value)
        {
            this.encoding = value;
            return this;
        }
        #endregion // TextWriter Property Setters
        #endregion // TextWriter Properties
    
    
        #region Construction/Destruction
        public TextWriterMulti(System.Collections.Generic.IEnumerable<System.IO.TextWriter> writers)
        {
            this.Clear();
            this.AddWriters(writers);
        }
        #endregion // Construction/Destruction
    
        #region Public interface
        public TextWriterMulti Clear()
        {
            this.writers.Clear();
            return this;
        }
    
        public TextWriterMulti AddWriter(System.IO.TextWriter writer)
        {
            this.writers.Add(writer);
            return this;
        }
    
        public TextWriterMulti AddWriters(System.Collections.Generic.IEnumerable<System.IO.TextWriter> writers)
        {
            this.writers.AddRange(writers);
            return this;
        }
        #endregion // Public interface
    
        #region TextWriter methods
    
        public override void Close()
        {
            foreach (System.IO.TextWriter writer in this.writers)
            {
                writer.Close();
            }
            base.Close();
        }
    
        protected override void Dispose(bool disposing)
        {
            foreach (System.IO.TextWriter writer in this.writers)
            {
                if (disposing)
                {
                    writer.Dispose();
                }
            }
            base.Dispose(disposing);
        }
    
        public override void Flush()
        {
            foreach (System.IO.TextWriter writer in this.writers)
            {
                writer.Flush();
            }
    
            base.Flush();
        }
    
        //foreach (System.IO.TextWriter writer in this.writers)
        //{
        //    writer;
        //}
        public override void Write(bool value)
        {
            foreach (System.IO.TextWriter writer in this.writers)
            {
                writer.Write(value);
            }
        }
    
        public override void Write(char value)
        {
            foreach (System.IO.TextWriter writer in this.writers)
            {
                writer.Write(value);
            }
        }
    
        public override void Write(char[] buffer)
        {
            foreach (System.IO.TextWriter writer in this.writers)
            {
                writer.Write(buffer);
            }
        }
    
        public override void Write(decimal value)
        {
            foreach (System.IO.TextWriter writer in this.writers)
            {
                writer.Write(value);
            }
        }
    
        public override void Write(double value)
        {
            foreach (System.IO.TextWriter writer in this.writers)
            {
                writer.Write(value);
            }
        }
    
        public override void Write(float value)
        {
            foreach (System.IO.TextWriter writer in this.writers)
            {
                writer.Write(value);
            }
        }
    
        public override void Write(int value)
        {
            foreach (System.IO.TextWriter writer in this.writers)
            {
                writer.Write(value);
            }
        }
    
        public override void Write(long value)
        {
            foreach (System.IO.TextWriter writer in this.writers)
            {
                writer.Write(value);
            }
        }
    
        public override void Write(object value)
        {
            foreach (System.IO.TextWriter writer in this.writers)
            {
                writer.Write(value);
            }
        }
    
        public override void Write(string value)
        {
            foreach (System.IO.TextWriter writer in this.writers)
            {
                writer.Write(value);
            }
        }
    
        public override void Write(uint value)
        {
            foreach (System.IO.TextWriter writer in this.writers)
            {
                writer.Write(value);
            }
        }
    
        public override void Write(ulong value)
        {
            foreach (System.IO.TextWriter writer in this.writers)
            {
                writer.Write(value);
            }
        }
    
        public override void Write(string format, object arg0)
        {
            foreach (System.IO.TextWriter writer in this.writers)
            {
                writer.Write(format, arg0);
            }
    
        }
    
        public override void Write(string format, params object[] arg)
        {
            foreach (System.IO.TextWriter writer in this.writers)
            {
                writer.Write(format, arg);
            }
        }
    
        public override void Write(char[] buffer, int index, int count)
        {
            foreach (System.IO.TextWriter writer in this.writers)
            {
                writer.Write(buffer, index, count);
            }
        }
    
        public override void Write(string format, object arg0, object arg1)
        {
            foreach (System.IO.TextWriter writer in this.writers)
            {
                writer.Write(format, arg0, arg1);
            }
        }
    
        public override void Write(string format, object arg0, object arg1, object arg2)
        {
            foreach (System.IO.TextWriter writer in this.writers)
            {
                writer.Write(format, arg0, arg1, arg2);
            }
        }
    
        public override void WriteLine()
        {
            foreach (System.IO.TextWriter writer in this.writers)
            {
                writer.WriteLine();
            }
        }
    
        public override void WriteLine(bool value)
        {
            foreach (System.IO.TextWriter writer in this.writers)
            {
                writer.WriteLine(value);
            }
        }
    
        public override void WriteLine(char value)
        {
            foreach (System.IO.TextWriter writer in this.writers)
            {
                writer.WriteLine(value);
            }
        }
    
        public override void WriteLine(char[] buffer)
        {
            foreach (System.IO.TextWriter writer in this.writers)
            {
                writer.WriteLine(buffer);
            }
        }
    
        public override void WriteLine(decimal value)
        {
            foreach (System.IO.TextWriter writer in this.writers)
            {
                writer.WriteLine(value);
            }
        }
    
        public override void WriteLine(double value)
        {
            foreach (System.IO.TextWriter writer in this.writers)
            {
                writer.WriteLine(value);
            }
        }
    
        public override void WriteLine(float value)
        {
            foreach (System.IO.TextWriter writer in this.writers)
            {
               writer.WriteLine(value);
            }
        }
    
        public override void WriteLine(int value)
        {
            foreach (System.IO.TextWriter writer in this.writers)
            {
                writer.WriteLine(value);
            }
        }
    
        public override void WriteLine(long value)
        {
            foreach (System.IO.TextWriter writer in this.writers)
            {
                writer.WriteLine(value);
            }
        }
    
        public override void WriteLine(object value)
        {
            foreach (System.IO.TextWriter writer in this.writers)
            {
                writer.WriteLine(value);
            }
        }
    
        public override void WriteLine(string value)
        {
            foreach (System.IO.TextWriter writer in this.writers)
            {
                writer.WriteLine(value);
            }
        }
    
        public override void WriteLine(uint value)
        {
            foreach (System.IO.TextWriter writer in this.writers)
            {
                writer.WriteLine(value);
            }
        }
    
        public override void WriteLine(ulong value)
        {
            foreach (System.IO.TextWriter writer in this.writers)
            {
                writer.WriteLine(value);
            }
        }
    
        public override void WriteLine(string format, object arg0)
        {
            foreach (System.IO.TextWriter writer in this.writers)
            {
                writer.WriteLine(format, arg0);
            }
        }
    
        public override void WriteLine(string format, params object[] arg)
        {
            foreach (System.IO.TextWriter writer in this.writers)
            {
                writer.WriteLine(format, arg);
            }
        }
    
        public override void WriteLine(char[] buffer, int index, int count)
        {
            foreach (System.IO.TextWriter writer in this.writers)
            {
                writer.WriteLine(buffer, index, count);
            }
        }
    
        public override void WriteLine(string format, object arg0, object arg1)
        {
            foreach (System.IO.TextWriter writer in this.writers)
            {
                writer.WriteLine(format, arg0, arg1);
            }
        }
    
        public override void WriteLine(string format, object arg0, object arg1, object arg2)
        {
            foreach (System.IO.TextWriter writer in this.writers)
            {
                writer.WriteLine(format, arg0, arg1, arg2);
            }
        }
        #endregion // TextWriter methods
    }
    

    【讨论】:

      【解决方案2】:

      我使用log4net 而不是标准的 I/O 工具来处理这类事情。我使用 ConsoleAppender 和 FileAppender 或 RollingFileAppender 将 log4net 配置为同时登录到控制台和日志文件。

      好处是您可以设置日志消息模板,以捕获除了记录的消息之外的各种有用信息(时间、线程/进程 ID、机器名称等)。

      您还可以登录到 SQL Server、事件日志或远程接收器。

      简单!

      这是一个通过 log4net 路由所有内容的示例 TextWriter 实现:

      using System;
      using System.IO;
      using System.Text;
      using log4net ;
      
      namespace ConsoleApplication22
      {
          public class Log4NetTextWriter : TextWriter, IDisposable
          {
              private static ILog log = log4net.LogManager.GetLogger( typeof(Log4NetTextWriter) ) ;
      
              #region properties
      
              private StringBuilder buffer { get ; set ; }
      
              public override Encoding Encoding
              {
                  get
                  {
                      // since this TextWrite is writing to log4net, we have no idea what the final encoding might be.
                      // It all depends on the log4net configuration: tthe appender or appenders that wind up handling the logged message
                      // determine the final encoding.
                      //
                      // Might make more sense to return Encoding.UTF8 though, just to return something.
                      throw new NotImplementedException() ;
                  }
              }
      
              #endregion properties ;
      
              public override void Flush()
              {
                  if ( this.buffer != null && this.buffer.Length > 0 )
                  {
                      this.WriteLine() ;
                  }
                  return ;
              }
      
              public override void Close()
              {
                  base.Close();
              }
      
              protected override void Dispose( bool disposing )
              {
                  this.Flush() ;
                  base.Dispose( disposing );
              }
      
              #region public constructors
      
              public Log4NetTextWriter() : this( null )
              {
                  return ;
              }
      
              public Log4NetTextWriter( IFormatProvider formatProvider ) : base( formatProvider )
              {
                  this.buffer = new StringBuilder() ;
              }
      
              #endregion public constructors
      
              #region public Write() overloads
              public override void Write( bool value )
              {
                  this.buffer.Append( value ) ;
                  return ;
              }
              public override void Write( char value )
              {
                  this.buffer.Append( value ) ;
                  return ;
              }
              public override void Write( char[] buffer )
              {
                  this.buffer.Append( buffer ) ;
                  return ;
              }
              public override void Write( char[] buffer , int index , int count )
              {
                  this.buffer.Append( buffer , index , count ) ;
                  return ;
              }
              public override void Write( decimal value )
              {
                  this.buffer.Append( value ) ;
                  return ;
              }
              public override void Write( double value )
              {
                  this.buffer.Append( value ) ;
                  return ;
              }
              public override void Write( float value )
              {
                  this.buffer.Append( value ) ;
                  return ;
              }
              public override void Write( int value )
              {
                  this.buffer.Append( value ) ;
                  return ;
              }
              public override void Write( long value )
              {
                  this.buffer.Append( value ) ;
                  return ;
              }
              public override void Write(object value)
              {
                  this.buffer.Append( value ) ;
                  return ;
              }
              public override void Write( string format , object arg0 )
              {
                  this.buffer.AppendFormat( this.FormatProvider , format , arg0 ) ;
                  return ;
              }
              public override void Write( string format , object arg0 , object arg1 )
              {
                  this.buffer.AppendFormat( this.FormatProvider , format , arg0 , arg1 ) ;
                  return ;
              }
              public override void Write( string format , object arg0 , object arg1 , object arg2 )
              {
                  this.buffer.AppendFormat( this.FormatProvider , format , arg0 , arg1 , arg2 );
                  return ;
              }
              public override void Write( string format , params object[] arg )
              {
                  this.buffer.AppendFormat( this.FormatProvider , format , arg ) ;
                  return ;
              }
              public override void Write( string value )
              {
                   this.buffer.Append( value );
                  return ;
              }
              public override void Write( uint value )
              {
                  this.buffer.Append( value );
                  return ;
              }
              public override void Write( ulong value )
              {
                  this.buffer.Append( value );
                  return ;
              }
              public override void WriteLine()
              {
                  string logMessage = this.buffer.ToString() ;
      
                  this.buffer.Length = 0 ;
                  log.Info( logMessage ) ;
      
                  return ;
              }
      
              #endregion public Write() overloads
      
              #region public WriteLine() overloads
      
              public override void WriteLine( bool value )
              {
                  this.Write( value ) ;
                  this.WriteLine() ;
                  return ;
              }
              public override void WriteLine( char value )
              {
                  this.Write( value ) ;
                  this.WriteLine() ;
                  return ;
              }
              public override void WriteLine( char[] buffer )
              {
                  this.Write( buffer ) ;
                  this.WriteLine() ;
                  return ;
              }
              public override void WriteLine( char[] buffer , int index , int count )
              {
                  this.Write( buffer , index , count ) ;
                  this.WriteLine() ;
                  return ;
              }
              public override void WriteLine( decimal value )
              {
                  this.Write( value ) ;
                  this.WriteLine() ;
                  return ;
              }
              public override void WriteLine( double value )
              {
                  this.Write( value ) ;
                  this.WriteLine() ;
                  return ;
              }
              public override void WriteLine( float value )
              {
                  this.Write( value ) ;
                  this.WriteLine() ;
                  return ;
              }
              public override void WriteLine( int value )
              {
                  this.Write( value ) ;
                  this.WriteLine() ;
                  return ;
              }
              public override void WriteLine( long value )
              {
                  this.Write( value ) ;
                  this.WriteLine() ;
                  return ;
              }
              public override void WriteLine( object value )
              {
                  this.Write( value ) ;
                  this.WriteLine() ;
                  return ;
              }
              public override void WriteLine( string format , object arg0 )
              {
                  this.Write( format , arg0 ) ;
                  this.WriteLine() ;
                  return ;
              }
              public override void WriteLine( string format , object arg0 , object arg1 )
              {
                  this.Write( format , arg0 , arg1 ) ;
                  this.WriteLine() ;
                  return ;
              }
              public override void WriteLine( string format , object arg0 , object arg1 , object arg2 )
              {
                  this.Write( format , arg0 , arg1 , arg2 ) ;
                  this.WriteLine() ;
                  return ;
              }
              public override void WriteLine( string format , params object[] arg )
              {
                  this.Write( format , arg ) ;
                  this.WriteLine() ;
                  return ;
              }
              public override void WriteLine( string value )
              {
                  this.Write( value ) ;
                  this.WriteLine() ;
                  return ;
              }
              public override void WriteLine( uint value )
              {
                  this.Write( value ) ;
                  this.WriteLine() ;
                  return ;
              }
              public override void WriteLine( ulong value )
              {
                  this.Write( value ) ;
                  this.WriteLine() ;
                  return ;
              }
      
              #endregion public WriteLine() overloads
      
          }
      }
      

      这是一个示例 log4net 配置文件。此日志记录到控制台和日志文件,并根据大小自动滚动(它也可以根据日期/时间或每次执行滚动)。

      <log4net>
      
        <!-- Log to the console -->
        <appender name="Console" type="log4net.Appender.ConsoleAppender">
          <layout type="log4net.Layout.PatternLayout">
            <!-- Pattern to output the caller's file name and line number -->
            <conversionPattern value="%5level [%thread] (%file:%line) - %message%newline" />
          </layout>
        </appender>
      
        <!-- Log to a log file. This particular setup should log to a static file name 'log.txt' -->
        <!-- When it hits 100KB in size, it rolls, keeping up to 10 archived files. The archived -->
        <!-- files are named 'log.text.1', 'log.txt.2', ... , 'log.txt.10' -->
        <appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender">
          <file value="log.txt" />
          <appendToFile value="true" />
          <rollingStyle value="Size" />
          <maxSizeRollBackups value="10" />
          <maximumFileSize value="100KB" />
          <staticLogFileName value="true" />
          <layout type="log4net.Layout.PatternLayout">
            <conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline" />
          </layout>
        </appender>
      
        <root>
          <level value="DEBUG" />
          <appender-ref ref="Console" />
          <appender-ref ref="RollingFile" />
        </root>
      
      </log4net>
      

      要配置 log4net,最简单的方法是在 AssemblyInfo.cs 中放置一个 XmlConfigurator 属性,因此:

      // Configure log4net using the .log4net file
      [assembly: log4net.Config.XmlConfigurator(ConfigFileExtension="log4net",Watch=true)]
      // This will cause log4net to look for a configuration file
      // called TestApp.exe.log4net in the application base
      // directory (i.e. the directory containing TestApp.exe)
      // The config file will be watched for changes.
      

      当您的程序运行时,您可以打开或关闭登录,或者只需编辑并保存配置文件即可更改其配置。 log4net 监视配置文件的更改并即时重新配置。

      【讨论】:

      • 我不是 log4net 方面的专家,但除非它允许我创建一个可以传递给这个外部库的 TextWriter 对象,否则这对我的问题不起作用......
      • @Nitax:请参阅上面我的答案的补充
      【解决方案3】:

      你的第一个猜测是正确的。您可以对其进行概括并编写一个“分布式”文本编写器,该文本编写器接受一个文本编写器列表作为构建时间参数,并将接收到的所有输入分发给每个文本编写器。

      【讨论】:

      • 好吧,使用这种方法,我假设我的 DistributingTextWriter 将持有对控制台 TextWriter 和 StreamWriter 的引用。然后我是否必须覆盖每个 Write 和 WriteLine 方法才能将这些调用“分发”给所有 TextWriter?
      • 恐怕是这样:如果要保持与 TextWriter 类接口的兼容性,就必须重新实现所有这些方法。但是,您可以从 System.IO.StreamWriter 的实现中复制大部分代码。谷歌搜索“SSCLI”和/或“Rotor”来找到它。
      【解决方案4】:

      您可以将数据副本发送到流(文本文件)和显示(控制台)。

      【讨论】:

        猜你喜欢
        • 2021-11-29
        • 1970-01-01
        • 2018-10-22
        • 1970-01-01
        • 2018-09-22
        • 2014-12-20
        • 1970-01-01
        • 1970-01-01
        • 2018-11-18
        相关资源
        最近更新 更多