FileSystemWatcher Not recognizing change in directory - c#

So I am trying to create a console application that will watch a directory and when a folder is dropped into the directory it will optimize the files inside of the folder. The optimization part is working. I am currently concerned with the fact that once I run the program with the FileSystemWatcher it never recognizes the change. Is the class only focusing on the root directory and not going any deeper?
I also saw on Microsoft's website that the way to watch for a file that has been copy pasted or moved into the directory is by using FileSystemWatcher.Renamed instead of .Changed which is what I was having an issue with before.
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net.Mime;
using System.Runtime.CompilerServices;
using System.Threading;
using pdftron;
using pdftron.Common;
using pdftron.Filters;
using pdftron.SDF;
using pdftron.PDF;
using OptimizerTestCS;
namespace PDFNetSamples
{
class Class1
{
private static pdftron.PDFNetLoader pdfNetLoader = pdftron.PDFNetLoader.Instance();
public static void Optimize()
{
Thread.Sleep(1000);
PDFNet.Initialize();
string input_Path = #"C:\Users\user\Desktop\testinp\";
string output_Path = #"C:\Users\user\Desktop\output\";
string[] files = Directory.GetFiles(input_Path, "*.pdf", SearchOption.AllDirectories);
foreach (string file in files)
{
string fileName = Path.GetFileName(file);
Console.WriteLine($"Optimizing {fileName}");
string sub = file.Substring(35, 7);
CreateFolder(output_Path + sub);
try
{
using (PDFDoc doc = new PDFDoc(file))
{
doc.InitSecurityHandler();
Optimizer.Optimize(doc);
doc.Save(output_Path + sub + fileName, SDFDoc.SaveOptions.e_linearized);
Console.WriteLine("Done..\n");
}
}
catch (PDFNetException e)
{
Console.WriteLine(e.Message);
}
}
}
private static void Run()
{
string[] args = Environment.GetCommandLineArgs();
if (args.Length != 2)
{
Thread.Sleep(3000);
Console.WriteLine("Usage: Watcher.exe (directory)");
return;
}
using (FileSystemWatcher watcher = new FileSystemWatcher())
{
watcher.Path = #"C:\Users\user\Desktop\testinp\";
watcher.NotifyFilter = NotifyFilters.LastAccess
| NotifyFilters.LastWrite
| NotifyFilters.FileName
| NotifyFilters.DirectoryName;
watcher.Filter = "*.pdf";
watcher.Renamed += OnChanged;
watcher.EnableRaisingEvents = true;
Console.WriteLine("Press 'q' to quit the sample.");
while (Console.Read() != 'q') ;
}
}
private static void OnChanged(object source, FileSystemEventArgs e) =>
Optimize();
static void CreateFolder(string path)
{
Directory.CreateDirectory(path);
}
public static void Main(string[] args)
{
while (true)
{
Run();
}
}
}
}

Add watcher.IncludeSubdirectories = true; to include sub directories.

You need to set the IncludeSubdirectories property to true.

Like others already said, you need to add watcher.IncludeSubdirectories = true;.
I guess your Optimize Method is not working cause of the input_path, which should be different for sub-directories as it's no longer input_path + filename.
So that said, you need to adjust your input_path to match the directory which you are tracking at the moment.

Related

Error when I trying to move a file in c# to an other folder with a listener on the first folder

Hello I have an error with file.Move a file to an other file with a listener to this specific folder,
I want move the file in Archive folder when a new file incomming on the folder Pending.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Permissions;
using System.Text;
using System.Threading.Tasks;
namespace ListenApp
{
class Program
{
public static class Globals
{
public static string args = "//lux.pbk/Profiles/LUX/BI14H/ProfilADW7/Desktop/trade/Pending/";
public static string archivePath = "//lux.pbk/Profiles/LUX/BI14H/ProfilADW7/Desktop/trade/archive/";
}
public static void Main()
{
Run();
}
[PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
private static void Run()
{
/* // If a directory is not specified, exit program.
if (args.Length != 2)
{
// Display the proper way to call the program.
Console.WriteLine("Usage: Watcher.exe (directory)");
return;
}*/
// Create a new FileSystemWatcher and set its properties.
using (FileSystemWatcher watcher = new FileSystemWatcher())
{
watcher.Path = Globals.args;
// Watch for changes in LastAccess and LastWrite times, and
// the renaming of files or directories.
watcher.NotifyFilter = NotifyFilters.LastAccess
| NotifyFilters.LastWrite
| NotifyFilters.FileName
| NotifyFilters.DirectoryName;
// Only watch text files.
watcher.Filter = "*.txt";
// Add event handlers.
watcher.Created += OnChanged;
// Begin watching.
watcher.EnableRaisingEvents = true;
// Wait for the user to quit the program.
Console.WriteLine("Press 'q' to quit the sample.");
while (Console.Read() != 'q') ;
}
}
// Define the event handlers.
private static void OnChanged(object source, FileSystemEventArgs e)
{
// Specify what is done when a file is changed, created, or deleted.
Console.WriteLine($"File: {e.FullPath} {e.ChangeType}");
Console.WriteLine(e.Name);
if(File.Exists(Globals.args + e.Name))
{
File.Move(Globals.args + e.Name, Globals.archivePath + e.Name); // System.IO.IOException: 'The process cannot access the file because it is being used by another process.'
}
}
}
}
On File.Move, I have a error, that said :
System.IO.IOException: 'The process cannot access the file because it
is being used by another process.'
How fix this?

System.Collections.ListDictionaryInternal Error

I'm trying to create a program where every time i create a text file,it will compress the file and log it .
It works for the first text file but when i create the second one, i get this exception: System.Collections.ListDictionaryInternal
Error:The process cannot access the file 'D:\TemeC#\FilesHomework\FilesHomework\ obj\Debug\New Text Document.txt' because it is being used by another process.
This is my code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.IO;
using System.IO.Compression;
using System.Security.Permissions;
namespace FilesHomework
{
class Program
{
static void Main(string[] args)
{
Run();
}
[PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
public static void Run()
{
FileSystemWatcher watcher = new FileSystemWatcher();
watcher.Path = "D:";
watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite
| NotifyFilters.FileName | NotifyFilters.DirectoryName;
watcher.Filter = "*.txt";
watcher.Created += new FileSystemEventHandler(OnChanged);
watcher.EnableRaisingEvents = true;
Console.WriteLine("Press \'q\' to quit the sample.");
while (Console.Read() != 'q') ;
}
private static void OnChanged(object source, FileSystemEventArgs e)
{
try {
FileInfo FileIn = new FileInfo(e.Name);
Compress(FileIn);
// FileStream LogFile = File.Open("LogFile.txt",FileMode.OpenOrCreate,FileAccess.ReadWrite,FileShare.ReadWrite);
// File.SetAttributes("LogFile.txt", FileAttributes.Normal);
// StreamWriter sw = new StreamWriter(LogFile);
string str;
str = ("The file " + e.Name + " has been deleted at " + DateTime.Now);
// byte[] b1 = System.Text.Encoding.UTF8.GetBytes(str);
// sw.WriteLine(str);
Console.WriteLine(str);
File.Delete(e.Name);
// LogFile.Close();
// sw.Close();
}
catch(Exception er)
{
Console.WriteLine("Error:" + er.Data);
}
}
public static void Compress(FileInfo fileSelected)
{
using (FileStream originalFileStream = fileSelected.OpenRead())
{
if ((File.GetAttributes(fileSelected.FullName) &
FileAttributes.Hidden) != FileAttributes.Hidden & fileSelected.Extension != ".gz")
{
using (FileStream compressedFileStream = File.Create(fileSelected.Name+ ".gz"))
{
using (GZipStream compressionStream = new GZipStream(compressedFileStream,
CompressionMode.Compress))
{
originalFileStream.CopyTo(compressionStream);
}
}
}
}
}
}
}
What do you guys think i should do?
Ahh, I think I see the problem.
It looks like your code is trying to pick up the new file, before you actually close the file in your editor.
You need to introduce a mechanism into your Compress method that checks if the file is available to open first.
See this answer to check if a file can be accessed or not, in code:
Is there a way to check if a file is in use?
Edit:
I would also try changing the FileSystemWatcher event you use to be .Changed, which fires after a file attribute is changed.
I would still check you can Open it to read by the link above though.

File written 3 times C#

I have this code that is being repeated 3 times:
private static void convert(object source, FileSystemEventArgs f)
{
string FileName;
FileName = f.FullPath;
string destinationFile = #"Y:\test\test.xml";
System.Threading.Thread.Sleep(2000);
try
{
Encoding utf8 = new UTF8Encoding(false);
Encoding ansi = Encoding.GetEncoding(1256);
System.Threading.Thread.Sleep(2000);
string xml = File.ReadAllText(FileName, ansi);
XDocument xmlDoc = XDocument.Parse(xml);
**Console.WriteLine("1st");**
File.WriteAllText(
destinationFile,
#"<?xml version=""1.0"" encoding=""utf-8""?>" + xmlDoc.ToString(),
utf8
);
}
Check the above in bold. It writes out 3 times. I have just put that to test. But why does it write out 3 times.. Meaning the file being written is also written 3 times.
I'm calling this function from a filesystemwatcher function to watch a folder if it has changed then take the file convert it to utf-8 and put it in the destination file.
EDIT 1:
Here is my watcher. Can you please check if this is fine:
private static void WatchFile()
{
watcher.Path = #"C:\project";
watcher.NotifyFilter = NotifyFilters.LastWrite;
watcher.Filter = "*.xml";
watcher.Changed += new FileSystemEventHandler(convert);
watcher.Error += new ErrorEventHandler(WatcherError);
Console.WriteLine("2nd");
watcher.EnableRaisingEvents = true;
}
Still don't have a clue why it gets repeated 3 times.
EDIT 2:
Here goes' my complete code:
using System;
using System.IO;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using System.Collections.Generic;
using System.Linq;
class Test
{
class Class1
{
private static FileSystemWatcher watcher =
new FileSystemWatcher();
public static void Main()
{
WatchFile();
Console.ReadLine();
}
private static void WatchFile()
{
watcher.Path = #"C:\project";
watcher.NotifyFilter = NotifyFilters.LastWrite;
watcher.Filter = "*.xml";
watcher.Changed += new FileSystemEventHandler(convert);
watcher.Error += new ErrorEventHandler(WatcherError);
Console.WriteLine("2nd");
watcher.EnableRaisingEvents = true;
}
public static string CrL = "\r\n";
private static void convert(object source, FileSystemEventArgs f)
{
string FileName;
FileName = f.FullPath;
string destinationFile = #"Y:\test\OnAirNow.xml";
System.Threading.Thread.Sleep(2000);
try
{
Encoding utf8 = new UTF8Encoding(false);
Encoding ansi = Encoding.GetEncoding(1256);
System.Threading.Thread.Sleep(2000);
string xml = File.ReadAllText(FileName, ansi);
XDocument xmlDoc = XDocument.Parse(xml);
Console.WriteLine("1st");
File.WriteAllText(
destinationFile,
#"<?xml version=""1.0"" encoding=""utf-8""?>" + xmlDoc.ToString(),
utf8
);
}
catch (Exception e)
{
Console.WriteLine("The process failed: {0}", e.ToString());
}
}
private static void WatcherError(object source, ErrorEventArgs e)
{
Exception watchException = e.GetException();
watcher = new FileSystemWatcher();
while (!watcher.EnableRaisingEvents)
{
try
{
WatchFile();
Console.WriteLine("I'm Back!!");
}
catch
{
System.Threading.Thread.Sleep(2000);
}
}
}
}
}
A common pattern using FileSystemWatcher is to set EnableRaisingEvents to false when starting processing the event:
this.fileSystemWatcher = new FileSystemWatcher()
{
Path = AppDomain.CurrentDomain.SetupInformation.ApplicationBase,
NotifyFilter = NotifyFilters.LastWrite,
Filter = Path.GetFileName(AppDomain.CurrentDomain.SetupInformation.ConfigurationFile)
};
this.fileSystemWatcher.Changed += this.ConfigChanged;
this.fileSystemWatcher.EnableRaisingEvents = true;
and
public void ConfigChanged(object sender, FileSystemEventArgs e)
{
try
{
this.fileSystemWatcher.EnableRaisingEvents = false;
s_logger.Info("Configuration file changed.");
// reload config here
s_logger.Info("Configuration settings reloaded.");
}
catch (Exception exception)
{
s_logger.Error(exception.Message);
s_logger.Error("Failed to reload configuration settings.");
}
finally
{
this.fileSystemWatcher.EnableRaisingEvents = true;
}
}
The FileSystemWatcher might raise more than one event for one file change, check it out:
Common file system operations might raise more than one event. For example, when a file is moved from one directory to another, several OnChanged and some OnCreated and OnDeleted events might be raised. Moving a file is a complex operation that consists of multiple simple operations, therefore raising multiple events. Likewise, some applications (for example, antivirus software) might cause additional file system events that are detected by FileSystemWatcher.
FileSystemWatcher Class in MSDN

exception rise with FileSystemWatcher

I wrote small app for monitoring file for changes.
When I run it, every time I get exception about Path. And I can't understand why. The path is really exist.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Run();
}
public static void Run()
{
FileSystemWatcher watcher = new FileSystemWatcher();
watcher.Path = #"D:\test\1.txt";
watcher.NotifyFilter = NotifyFilters.LastWrite;
watcher.Changed +=new FileSystemEventHandler(watcher_Changed);
watcher.EnableRaisingEvents = true;
}
static void watcher_Changed(object sender, FileSystemEventArgs e)
{
Console.WriteLine(e.ChangeType);
}
}
}
FileSystemWatcher.Path should be a Path not a file name
watcher.Path = #"D:\test";
watcher.Filter = "1.txt";
private static void watcher_Changed(object source, FileSystemEventArgs e)
{
// this test is unnecessary if you plan to monitor only this file and
// have used the proper constructor or the filter property
if(e.Name == "1.txt")
{
WatcherChangeTypes wct = e.ChangeType;
Console.WriteLine("File {0} {1}", e.FullPath, wct.ToString());
}
}
You can also limit the monitoring using the constructor that takes two parameters, the path and a file filter.
FileSystemWatcher watcher = new FileSystemWatcher(#"d:\test", "1.txt");
See MSDN References

Filesystemwatcher does not raise rename event handler in C# on Windows7

I am using C# 3.5 on Windows 7. We have implemented a program with a FileSystemWatcher. Here, rename event is not raised. But it is working on a few systems.
What could be causing this?
There may be a timing window in your code such that not all filesystem events are properly captured on all your systems. Can you post it?
It is a 'feature' of the underlying Win32 API ReadDirectoryChangesW and hence FileSystemWatcher that under heavy load, events can get missed. There are mitigation suggestions in the MSDN docs.
Make sure that you set your watcher:
fileSystemWatcher.EnableRaisingEvents = true;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Security.AccessControl;
using System.Security.Permissions;
using System.Text;
using System.Windows.Forms;
namespace Watcher
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
FileRenamed();
}
private static string _osLanguage = null;
[PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
private void FileRenamed()
{
MessageBox.Show("Code is Started Now");
// Create a new FileSystemWatcher and set its properties.
FileSystemWatcher watcher = new FileSystemWatcher();
SetDirectoryAccess(#"c:\temp");
watcher.Path = #"C:\Temp";
/* Watch for changes in LastAccess and LastWrite times, and
the renaming of files or directories. */
watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite
| NotifyFilters.FileName | NotifyFilters.DirectoryName;
// Only watch text files.
watcher.Filter = "*.txt";
// Add event handlers.
watcher.Changed += new FileSystemEventHandler(OnChanged);
watcher.Created += new FileSystemEventHandler(OnChanged);
watcher.Deleted += new FileSystemEventHandler(OnChanged);
watcher.Renamed += new RenamedEventHandler(OnRenamed);
watcher.Error += new ErrorEventHandler(OnError);
// Begin watching.
watcher.EnableRaisingEvents = true;
}
// Define the event handlers.
private static void OnChanged(object source, FileSystemEventArgs e)
{
// Specify what is done when a file is changed, created, or deleted.
//Console.WriteLine("File: " + e.FullPath + " " + e.ChangeType);
MessageBox.Show("Something is changed in the File");
}
private static void OnRenamed(object source, RenamedEventArgs e)
{
// Specify what is done when a file is renamed.
MessageBox.Show("File Is Renamed");
//WatcherChangeTypes wct = e.ChangeType;
//Console.WriteLine("File {0} {2} to {1}", e.OldFullPath, e.FullPath, wct.ToString());
}
// This method is called when the FileSystemWatcher detects an error.
private static void OnError(object source, ErrorEventArgs e)
{
MessageBox.Show("Error Trapped");
// Show that an error has been detected.
Console.WriteLine("The FileSystemWatcher has detected an error");
// Give more information if the error is due to an internal buffer overflow.
if (e.GetException().GetType() == typeof(InternalBufferOverflowException))
{
// This can happen if Windows is reporting many file system events quickly
// and internal buffer of the FileSystemWatcher is not large enough to handle this
// rate of events. The InternalBufferOverflowException error informs the application
// that some of the file system events are being lost.
Console.WriteLine(("The file system watcher experienced an internal buffer overflow: " + e.GetException().Message));
}
}
private void button1_Click(object sender, EventArgs e)
{
//File.Move(#"\\NAS\dossier_echange\Carl\temp\Test.txt", #"\\NAS\dossier_echange\Carl\temp\Test007.txt");
File.Move(#"c:\temp\Test.txt", #"c:\temp\Test007.txt");
}
internal static void SetDirectoryAccess(string directoryPathString)
{
string everyoneString;
if (OSLanguage.Equals("en-US"))
everyoneString = "Everyone";
else
everyoneString = "Tout le monde";
//sets the directory access permissions for everyone
DirectorySecurity fileSecurity = Directory.GetAccessControl(directoryPathString);
//creates the access rule for directory
fileSecurity.ResetAccessRule(new FileSystemAccessRule(everyoneString, FileSystemRights.FullControl, AccessControlType.Allow));
//sets the access rules for directory
Directory.SetAccessControl(directoryPathString, fileSecurity);
}
public static string OSLanguage
{
get
{
if (_osLanguage == null)
_osLanguage = CultureInfo.CurrentCulture.Name;
return _osLanguage;
}
set
{
_osLanguage = value;
}
}
}
}

Categories