FileSystemWatcher - How to pipe output to text file?
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.
精彩评论