I'm trying to create a simple app, what moves all files writed to some directory to other directory. That's my problem: if i write other than 10000 files at once in my directory(small .txt files over 1KB) - some of them not handling to move on output directory. I'm using FileSystemWatcher events handler to solve this problem. Here is my code example:
Class MyProgramm
{
void Process(Object o, FileSystemEventArgs e)
{
//do something with e.Name file
}
void main()
{
var FSW = New FileSystemWatcher{Path = "C:\\InputDir"};
FSW.Created += Process;
FSW.EnableRisingEvents = true;
Thread.Sleep(Timeout.Infinite);
}
}
Finally, we got some files processed, but some of written files stays unprocessed..
Any suggestions?
I had similar issues with the FileSystemWatcher. It seemed to "drop the ball" quite regularly. I went for an alternative solution by extending "ServiceBase", which has been working consistently since it went live as a windows service. Hope this helps:
public partial class FileMonitor : ServiceBase
{
private Timer timer;
private long interval;
private const string ACCEPTED_FILE_TYPE = "*.csv";
public FileMonitor()
{
this.ServiceName = "Service";
this.CanStop = true;
this.CanPauseAndContinue = true;
this.AutoLog = true;
this.interval = long.Parse(1000);
}
public static void Main()
{
ServiceBase.Run(new FileMonitor());
}
protected override void OnStop()
{
base.OnStop();
this.timer.Dispose();
}
protected override void OnStart(string[] args)
{
AutoResetEvent autoEvent = new AutoResetEvent(false);
this.timer = new Timer(new TimerCallback(ProcessNewFiles), autoEvent, interval, Timeout.Infinite);
}
private void ProcessNewFiles(Object stateInfo)
{
DateTime start = DateTime.Now;
DateTime complete = DateTime.Now;
try
{
string directoryToMonitor = "c:\mydirectory";
DirectoryInfo feedDir = new DirectoryInfo(directoryToMonitor);
FileInfo[] feeds = feedDir.GetFiles(ACCEPTED_FILE_TYPE, SearchOption.TopDirectoryOnly);
foreach (FileInfo feed in feeds.OrderBy(m => m.LastWriteTime))
{
// Do whatever you want to do with the file here
}
}
finally
{
TimeSpan t = complete.Subtract(start);
long calculatedInterval = interval - t.Milliseconds < 0 ? 0 : interval - t.Milliseconds;
this.timer.Change(calculatedInterval, Timeout.Infinite);
}
}
}
Related
I'm using NAudio to record a fixed length audio file, but it crashes after the first file at the TimerElapsed method.
I'm using a Timer that stops and starts a new recording after the Interval has elapsed.
The filename is changed after each new recording.
This is the error I get.
System.AccessViolationException
HResult=0x80004003
Message=Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
Source=<Cannot evaluate the exception source>
StackTrace:
<Cannot evaluate the exception stack trace>
The class code is here :
namespace AudioService
{
public class AudioRecorder
{
public string Location
{
get => location;
set
{
location = value;
Filename = $"{Location}/test001.wav";
}
}
public string Filename { get; set; }
public double Interval { get; set; } = 10000;
public int DeviceNumber { get; set; } = 0;
private WaveInEvent waveSource = null;
private WaveFileWriter waveFile = null;
public bool LoopRecord { get; set; } = true;
public bool Recording { get; set; } = false;
private System.Timers.Timer timer;
private string location;
public AudioRecorder()
{
Location = Environment.GetEnvironmentVariable("userprofile");
Filename = $"{Location}/test001.wav";
if (LoopRecord) setTimer();
}
private void setTimer()
{
timer = new System.Timers.Timer(Interval);
timer.Elapsed += Timer_Elapsed;
timer.AutoReset = true;
}
private void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
/// ****************
/// CRASHES HERE
/// ****************
waveSource?.StopRecording();
Filename = GetNewFileName();
StartRecording(Filename);
}
public void StartRecording()
{
if (timer != null)
timer.Enabled = true;
StartRecording(Filename);
}
public async void StartRecording(string filename)
{
if (waveSource == null)
{
waveSource = new WaveInEvent
{
DeviceNumber = DeviceNumber,
WaveFormat = new WaveFormat(44100, 1)
};
waveSource.DataAvailable += new EventHandler<WaveInEventArgs>(waveSource_DataAvailable);
waveSource.RecordingStopped += new EventHandler<StoppedEventArgs>(waveSource_RecordingStopped);
}
waveFile = await Task.Run(() => new WaveFileWriter(filename, waveSource.WaveFormat));
waveSource.StartRecording();
Recording = true;
}
private void waveSource_RecordingStopped(object sender, StoppedEventArgs e)
{
if (waveSource != null)
{
waveSource.Dispose();
waveSource = null;
}
if (waveFile != null)
{
waveFile.Dispose();
waveFile = null;
}
Recording = false;
}
private void waveSource_DataAvailable(object sender, WaveInEventArgs e)
{
if (waveFile != null)
{
waveFile.Write(e.Buffer, 0, e.BytesRecorded);
waveFile.Flush();
}
}
public void StopRecording()
{
waveSource?.StopRecording();
timer.Enabled = false;
}
public string GetNewFileName()
{
var tempLocation = $"{Location}/{DateTime.Now:yyMMdd}/";
bool folderExists = Directory.Exists(tempLocation);
if (!folderExists)
Directory.CreateDirectory(tempLocation);
string date = DateTime.Now.ToString("HH.mm.ss");
return $"{tempLocation}{date}.wav";
}
}
}
Thanks for helping
That exception basically means that you are crashing the 3rd party unmanaged code in NAudio, probably by trying to access an object that it is busy using or that it has already closed.
Your timer is going to fire every time your interval elapses, but you don't have any code to make sure that the previous recording is complete before starting a new one. In other words, StartRecording will get called over and over one the timer is started. If you want StartRecording to fire ONCE, then timer.AutoReset should be false.
A good way to troubleshoot these kind of issues is to replace all the calls to NAudio objects with console.writelines describing what is happening, and then run your program and observe the output.
I have a windows service that basically monitors a folder, copies files to a local directory processes the files. The service starts up fine enough calls the Watcher Class and does all of the configuration like it should. So my code works for the setup. However I get 0 events firing. I am wondering if when my StartFolderWatcher() method goes out of scope that my object - even though declared at the class level is somehow getting disposed.
So do I need to run the object continuously in a separate thread ? If so can I get an example of how I should do that Task.Run(()=> myObject)
Relevant Code is below - if more is needed just ask and I will post it.
static class Program
{
static void Main(string[] args)
{
JobProcessor service = new JobProcessor();
if (Environment.UserInteractive)
{
service.RunAsConsole(args);
}
}
private static bool IsDebugMode(string[] args)
{
if (args == null) return false;
if (args[0].ToLower() == "/debug") return true;
return false;
}
}
public partial class JobProcessor : ServiceBase
{
string[] folders = new string[] {"InBoxFolder"};
HotFolderWatch HFW = new HotFolderWatch();
public JobProcessor()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
StartFolderWatcher();
}
public void StartFolderWatcher()
{
FileWatcherInfo[] ServiceWatchers = new FileWatcherInfo[4];
ServiceConfiguration sc = new ServiceConfiguration();
for (int i = 0; i < folders.Length; i++)
{
ServiceWatchers[i] = sc.GetWatchFolderSettings(folders[i]);
}
HFW = new HotFolderWatch(ServiceWatchers[0]);
HFW.ReadyToProcess += ReadyToProcess;
HFW.InBoxFolderDisconnected += OnInBoxFolderDisconnected;
HFW.LocalFolderDisconnected += OnLocalFolderDisconnected;
HFW.ProcessFolderDisconnected += OnProcessFolderDisconnected;
}
public void RunAsConsole(string[] args)
{
OnStart(args);
Console.WriteLine("Press any key to exit...");
Console.ReadLine();
OnStop();
}
}
public HotFolderWatch(FileWatcherInfo inbox)
{
this.InboxCacheTimeMilliseconds = inbox.CacheTimeMilliseconds;
this.InBoxFolder = inbox.Folder.Trim();
this.InboxFileFilter = inbox.Filter.Trim();
SetInboxWatcher();
}
private void SetInboxWatcher()
{
InBoxWatcher = new FileSystemWatcher(InBoxFolder, InboxFileFilter);
InBoxWatcher.IncludeSubdirectories = false;
InBoxWatcher.NotifyFilter =
NotifyFilters.LastAccess | NotifyFilters.LastWrite;
InboxCache = MemoryCache.Default;
InboxCachePolicy = new CacheItemPolicy()
{
RemovedCallback = OnRemovedFromInBoxCache
};
InBoxWatcher.Created += new FileSystemEventHandler(OnInBoxChanged);
InBoxWatcher.EnableRaisingEvents = true;
}
private void OnInBoxChanged(object source, FileSystemEventArgs e)
{
InboxCachePolicy.AbsoluteExpiration =
DateTimeOffset.Now.AddMilliseconds(InboxCacheTimeMilliseconds);
InboxCache.AddOrGetExisting(e.Name, e, InboxCachePolicy);
}
}
If in my HotFolderWatch Class I create a FileSystemWatcher in a method as below the code works!
private void CreateWatcher()
{
FileSystemWatcher fsw = new FileSystemWatcher(#"C:\Tests\JobQueue\InFolder","*.txt");
fsw.Created += Fsw_Created;
fsw.EnableRaisingEvents = true;
}
private void Fsw_Created(object sender, FileSystemEventArgs e)
{
string ex = e.FullPath;
WatcherChangeTypes ctmp = e.ChangeType;
// throw new NotImplementedException();
}
Turns out the default constructor of FileSystemWatcher uses the filter FileName by default and I was thinking I would get a last Write or Last Access with out concerning myself with the Name.
I received good information from here :
https://www.codeproject.com/Articles/1220094/NotifyFilters-Enumeration-Explained-FileSystemWatc
The article posted in the link is what helped me to solve my issue.
I had to Ste the NotifyFilters.FileName as one of the filters.
I have a windows service implemented in C#. The service watches a number of directories for a file to be saved. However to make it more robust I am trying to get it to check the folders after a period of time.
The inner class called a Watcher initialises both the fileSystemWatcher and DispatchTimer.
public class Watcher
{
FileSystemWatcher fileSystemWatcher = null;
public delegate void TimerInvokedHandler(object sender);
public event TimerInvokedHandler TimerInvoked;
public DispatcherTimer Timer { get; set; }
public int TimerMinutes { get; set; }
public Watcher()
{
}
public Watcher(String directory, String filter, String dap)
{
this.DAP = dap;
this.Directory = directory;
this.Filter = filter;
}
public Boolean EnableRaisingTimerEvents
{
get { return this.Timer.IsEnabled; }
set
{
this.Timer.IsEnabled = value;
if (value)
{
this.Timer.Start();
Log("Timer Started");
}
else
{
this.Timer.Stop();
Log("Timer Stopped");
}
}
}
private void Timer_Tick(object sender, EventArgs e)
{
StopWatch();
TimerInvoked?.Invoke(sender);
}
public void StartWatch()
{
if (fileSystemWatcher == null)
{
fileSystemWatcher = new FileSystemWatcher();
fileSystemWatcher.Filter = Filter;
fileSystemWatcher.Path = Directory;
fileSystemWatcher.Created += FileSystemWatcher_Created;
fileSystemWatcher.Renamed += FileSystemWatcher_Renamed;
fileSystemWatcher.Error += FileSystemWatcher_Error;
}
if (this.Timer == null)
{
Log("Initialising Timer");
this.Timer = new DispatcherTimer();
this.Timer.Interval = new TimeSpan(0, this.TimerMinutes, 0);
this.Timer.Tick += Timer_Tick;
}
this.EnableRaisingFileSystemsEvents = true;
this.EnableRaisingTimerEvents = true;
Log(String.Format("Watching Directory {0}", Directory));
}
// stops timer and file system events
public void StopWatch()
{
if (fileSystemWatcher != null)
EnableRaisingFileSystemsEvents = false;
if (Timer != null)
{
EnableRaisingTimerEvents = false;
}
Log(String.Format("Watching {0} Switched Off", this.Directory));
}
private void Log ( String Message )
{
LogEvent?.Invoke(this, Message);
}
}
The outer class creates a list of these watchers, this is based on ServiceBase, as in it is a service and so only ends when it gets a stopped within the Windows Service Manager
foreach (nhs_acquisition_profile pfl in p)
{
Watcher w = null;
String filePattern = String.Empty;
try
{
profileWatcherLog.WriteEntry(String.Format("Attempting to set-up watcher on {0} for DAP {1}",pfl.dap_file_location,pfl.dap_name));
if (pfl.dap_acquisition_method_loca.ToLower() == "xml") w = new Watcher(pfl.dap_file_location, "*.xml", pfl.dap_name);
else w = new Watcher(pfl.dap_file_location, "*.*", pfl.dap_name);
profileWatcherLog.WriteEntry("Initialising Event Handlers");
// initialise event handlers
w.FileCreated += W_FileCreated;
w.FileRenamed += W_FileRenamed;
w.TimerInvoked += W_TimerInvoked;
w.LogEvent += W_LogEvent;
profileWatcherLog.WriteEntry("Event Handlers initialised");
// dispatch timer
w.TimerMinutes = Convert.ToInt32(Properties.Settings.Default.TimerDelay);
w.StartWatch();
profileWatcherLog.WriteEntry("Watch started....Adding to Watcher List");
// add the watcher to the list of watchers
FileWatcherList.Add(w);
profileWatcherLog.WriteEntry("Added to list of file watchers");
profileWatcherLog.WriteEntry(String.Format("Watching {0} for files matching *.* for DAP {1}",pfl.dap_file_location,pfl.dap_name));
}
catch
{
throw;
}
}
The variable FileWatcherList is a field of the ProfileWatcher class which forms the service as a whole.
What I am finding is that the DispatchTimer Tick event never happens. I'm reasonable certain that this is not an instance of the DispatchTimer being disposed of before the Tick, but can't see why it is not firing.
Dmitri is correct, I should have been using a Timer and not a DispatchTimer. Once I moved to that it worked fine.
I am implementing a winform application that is supposed to do the following:
OnLoad, open an XML file reading required information while watching for any new changes to the file (incoming new information)
A timer performing certain actions based on the nature of the provided information from the XML file. Please note that the nature of the action depends on the content of the XML file
What is the best way to achieve this? Two threads? Async? Some starting point would be much appreciated.
I think you need like this structure. Firstly you read XML file and configure your custom MyConfigurationClass object. After this point you can configure FileSystemWatcher object. And finally, you can configure your task schedular object with your desired time interval.
public partial class MainWindow : Window
{
MyConfigurationClass configuration;
string filePath = #"./some.xml";
FileSystemWatcher fileWatcher = new FileSystemWatcher();
System.Timers.Timer timer = new System.Timers.Timer();
public MainWindow()
{
// First read action action for
var task = Task.Run(() => ReadXML());
InitializeComponent();
FileWatherConfigure();
TimerConfigure(task.Result);
}
private void FileWatherConfigure()
{
fileWatcher.Path = System.IO.Path.GetDirectoryName(filePath);
fileWatcher.Filter = System.IO.Path.GetFileName(filePath);
fileWatcher.Changed += FileWatcher_Changed;
fileWatcher.EnableRaisingEvents = true;
}
private void TimerConfigure(SomeClass someClass)
{
timer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
timer.Interval = configuration.TimeInterval.TotalMilliseconds;
timer.Enabled = true;
}
private void FileWatcher_Changed(object sender, FileSystemEventArgs e)
{
Thread.Sleep(TimeSpan.FromSeconds(1));
SomeClass someClass = ReadXML();
// Do whatever you want file change
}
private void OnTimedEvent(object sender, ElapsedEventArgs e)
{
timer.Stop();
try
{
// Schedule Operation
}
catch (Exception ex)
{
}
timer.Start();
}
private SomeClass ReadXML()
{
// Read file and do what ever you want
}
}
public class SomeClass
{
// Data from XML
}
public class MyConfigurationClass
{
public TimeSpan TimeInterval { get; set; }
}
I have a service that processes files. Sometimes they process very quickly and sometimes they take a very long time. I can't control the process that sends the files to me. The are randomly dropped on me throughout the day and night. When I use the timer, it seems like the "ProcessFiles" method is abandoned whereever it is when the time has elapsed and ProcessFiles is called again. Since the files contain sensitive information, they can't sit on the server for a long time so I can't set the timer for any longer than 5 minutes and, still, at 5 minutes, the process sometimes interrupts itself. As a result, I have partially processed files. I would appreciate any thoughts and input on this quandary.
System.Timers.Timer _timer;
// As the files come in, massage them and encrypt them
public const string InPath = #"c:\input";
public const string OutPath = #"\c:\output";
public FileMassaging()
{
InitializeComponent();
}
public EventLog MyEventLog = new EventLog();
public string sSource = "FileMassaging";
public string sLog = "FileMassaging";
protected override void OnStart(string[] args)
{
// Create the source, if it does not already exist.
if (!EventLog.SourceExists(sSource))
EventLog.CreateEventSource(sSource, sLog);
// set up the service
ServiceStatus serviceStatus = new ServiceStatus();
serviceStatus.dwCurrentState = ServiceState.SERVICE_START_PENDING;
serviceStatus.dwWaitHint = 100000;
SetServiceStatus(this.ServiceHandle, ref serviceStatus);
// set up the service
_timer = new System.Timers.Timer();
_timer.Elapsed += new System.Timers.ElapsedEventHandler(this.OnTimer);
_timer.Interval = 5000;
_timer.Start();
// Update the service state to Running.
serviceStatus.dwCurrentState = ServiceState.SERVICE_RUNNING;
SetServiceStatus(this.ServiceHandle, ref serviceStatus);
}
public void OnTimer(object sender, System.Timers.ElapsedEventArgs args)
{
ProcessFiles();
}
public void ProcessFiles()
{
string[] originalFiles = Directory.GetFiles(InPath + #"\", "*.txt");
foreach (string fileName in originalFiles)
{
// Check and process the file
CheckFile(InPath, OutPath, fileName);
}
}
public void CheckFile(string InPath,Outpath, fileName)
{
// for example only -- actual file processing is much longer
//
string infile = InPath+fileName;
string outfile= OutPath+fileName;
File.Move(infile,outfile,true);
}
For testing and extensiblity I would recommend a different overall structure.
First let's seperate out this work into classes where it makes sense. Lets start with a class called FolderWatcher:
public class FolderWatcher
{
private readonly string _inPath;
private readonly string _outPath;
public bool CurrentlyRunning { get; set; }
public FolderWatcher(string inPath, string outPath)
{
_inPath = inPath;
_outPath = outPath;
}
public void TryProcessFiles(object sender, ElapsedEventArgs e)
{
try
{
this.CurrentlyRunning = true;
ProcessFiles(sender, e);
}
catch (Exception)
{
throw;
}
finally
{
this.CurrentlyRunning = false;
}
}
public void ProcessFiles(object sender, ElapsedEventArgs e)
{
string[] originalFiles = GetFilesInDirectory();
foreach (var originalFile in originalFiles)
{
CheckFile(originalFile);
}
}
// Internal/Virtual so that this can mocked in unit testing.
internal virtual string[] GetFilesInDirectory()
{
return Directory.GetFiles(_inPath + #"\", "*.txt");
}
// Internal/Virtual so that this can mocked in unit testing.
internal virtual void CheckFile(string fileName)
{
string infile = $"{_inPath}{fileName}";
string outfile = $"{_outPath}{fileName}";
File.Move(infile, outfile);
}
}
This class has a single responsibility, to move files in response to an event.
Next let's build a class to wrap the FolderWatcher class that handles the timer functionality:
public class TimedFolderWatcher
{
private readonly FolderWatcher _folderWatcher;
private readonly Timer _timer;
public TimedFolderWatcher(FolderWatcher folderWatcher)
{
_folderWatcher = folderWatcher;
InitTimer();
}
private void InitTimer()
{
_timer.Elapsed += new System.Timers.ElapsedEventHandler(this.ProcessFiles);
_timer.Interval = 5000;
_timer.Start();
}
private void ProcessFiles(object sender, ElapsedEventArgs e)
{
_folderWatcher.TryProcessFiles(sender, e);
}
}
This class also has a single responsibility to call the ProcessFiles method every 5000 milliseconds.
Lastly we can init and call these classes this way:
var fileMassageService = new TimedFolderWatcher(new FolderWatcher(#"c:\input", #"c:\output"));
This approach lends itself to testing and follows the best practices of Dependency Injection which will allow you to use an IOC framework in the future if you need to.
From the MSDN Page on Timers try this (https://msdn.microsoft.com/en-us/library/system.timers.timer.interval(v=vs.110).aspx)
_timer = new System.Timers.Timer(5);
_timer.Elapsed += OnTimer;
_timer.AutoReset = true;
// _timer.Start();
_timer.Enable = true;
private static void OnTimer(object sender, System.Timers.ElapsedEventArgs args) { ProcessFiles(); }