开发者

FileSystemWatcher - How to pipe output to text file?

开发者 https://www.devze.com 2023-03-07 14:42 出处:网络
I am using the FileSystemWatcher Class.I am trying to pipe the output to a text file.I have added the StreamWriter fileWriter = new StreamWriter(\"test.txt\"); but nothing is output to the file!Where

I am using the FileSystemWatcher Class. I am trying to pipe the output to a text file. I have added the StreamWriter fileWriter = new StreamWriter("test.txt"); but nothing is output to the file! Where am I going wrong?

class Program
{
    static void Main(string[] args)
    {
        string dirPath = "C:\\";

        FileSystemWatcher fileWatcher = new FileSystemWatcher(dirPath);
        fileWatcher.IncludeSubdirectories = true;
        fileWatcher.Filter = "*.exe";
        // fileWatcher.Filter = "C:\\$Recycle.Bin";
        //  fileWatcher.Changed += new FileSystemEventHandler(FileWatcher_Changed);
        fileWatcher.Created += new FileSystemEventHandler(FileWatcher_Created);
        //  fileWatcher.Deleted += new FileSystemEventHandler(FileWatcher_Deleted);
        //  fileWatcher.Renamed += new RenamedEventHandler(FileWa开发者_如何学Ctcher_Renamed);
        fileWatcher.EnableRaisingEvents = true;
        StreamWriter fileWriter = new StreamWriter("test.txt");
        Console.ReadKey();
    }
}


The code that actually writes to the output stream needs to be inside the FileWatcher_Created event handler. You can only write out that a file was created in the code that runs when a file is created.

That means that the event handler needs access to the StreamWriter you've created, or else it needs to open the output file itself, write a value, and then close it every time the event fires.

Since you can't pass the StreamWriter to the event handler as an argument, the only way to give the event handler access to it is to make it a class-level variable, which you can't do from a static Main method. You'll probably have to create a class to hold both the FileSystemWatcher and the StreamWriter, and just instantiate that class from the Main method.

But Wait, There's More!

What if you're in the process of writing to the StreamWriter, and another file gets created at that exact moment? You can't have two threads writing to a single StreamWriter at the same time, or Bad Things are inevitable. So you'll need to protect access to the StreamWriter using some sort of locking.


You need to call

fileWriter.Write(data);

Additionally, you should wrap it up like this:

using(StreamWriter fileWriter = new StreamWriter("test.txt"))
{
    fileWriter.Write(data);
    fileWriter.Flush(); // maybe not necessary
}

This will write data to the filesystem and it should trigger your FileSystemWatcher object.

edit -- inplace example

class Program
{    
    static void Main(string[] args)
    {
        string dirPath = "C:\\";
        FileSystemWatcher fileWatcher = new FileSystemWatcher(dirPath); 
        fileWatcher.IncludeSubdirectories = true;  
        fileWatcher.Filter = "*.exe";    
        // fileWatcher.Filter = "C:\\$Recycle.Bin";   
        //  fileWatcher.Changed += new FileSystemEventHandler(FileWatcher_Changed);   
        fileWatcher.Created += new FileSystemEventHandler(FileWatcher_Created);    
        //  fileWatcher.Deleted += new FileSystemEventHandler(FileWatcher_Deleted);  
        //  fileWatcher.Renamed += new RenamedEventHandler(FileWatcher_Renamed);    
        fileWatcher.EnableRaisingEvents = true;      

        // updated code
        using(StreamWriter fileWriter = new StreamWriter("test.txt"))
        {
            var data = true;
            fileWriter.Write(data);
        }

        Console.ReadKey(); 
    }
}


I'd just use Log4Net and not worry about thread safety or any of the other gory details.

Put this in your AssemblyInfo.cs:

[assembly: log4net.Config.XmlConfigurator(ConfigFile="Log4Net.config",Watch=true)]

Every class that's going to log something needs a logger. Put this in each such class definition:

private static readonly ILog Log = LogManager.GetLogger( MethodBase.GetCurrentMethod().DeclaringType ) ;

The reason for the above is that it identifies each logger by its containing type. Your log4net.config can filter/route/configure logging by logger, so by doing it this way, you get a great deal of control over the logging. You can, say, dial up the logging verbosity on a particular class that appears to be misbehaving, whilst leaving the rest of the application only logging stuff at, say, the ERROR and FATAL levels.

You can log a message via one of the ILog methods (just like Console.WriteLine() or string.Format():

Log.InfoFormat( "some-format-string" , ... ) ;

Set up your log4net.config file so it looks something like this:

<log4net>

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

  <appender name="RollingFile" type="log4net.Appender.RollingFileAppender">
    <file               value="example.log" />
    <appendToFile       value="true"        />
    <maximumFileSize    value="100KB"       />
    <maxSizeRollBackups value="2"           />
    <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%level %thread %logger - %message%newline" />
    </layout>
  </appender>

  <root>
    <level value="DEBUG" />
    <appender-ref ref="Console" />
    <appender-ref ref="RollingFile" />
  </root>

</log4net>

And you'll logging to the console and to a file. Log4Net will take care of log file rollover and all the icky bits.

0

精彩评论

暂无评论...
验证码 换一张
取 消