I'd like to continuously read in all image files from a folder on my local drive, then do some processing and end the program once all images have been read. The images numbers are not sequential they are random however they are located in a single folder. Currently my program can only read in one file; see code below
string imagePath = Path.Combine(Freconfig.GetSamplesFolder(), "24917324.jpg");
use FileSystemWatcher
https://msdn.microsoft.com/en-us/library/system.io.filesystemwatcher(v=vs.110).aspx
FileSystemWatcher watcher = new FileSystemWatcher();
watcher.Path = Freconfig.GetSamplesFolder();
watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite
| NotifyFilters.FileName | NotifyFilters.DirectoryName;
watcher.Filter = "*.jpg";
// Add event handlers.
watcher.Changed += new FileSystemEventHandler(OnChanged);
watcher.Created += new FileSystemEventHandler(OnChanged);
watcher.Deleted += new FileSystemEventHandler(OnChanged);
watcher.Renamed += new RenamedEventHandler(OnRenamed);
// Begin watching.
watcher.EnableRaisingEvents = true;
before starting watcher, use directorylisting to find all existing files and process them, then use watcher
Is this what you are looking for? Directory.GetFiles(#"..\somepath") (MSDN)
You could try:
directoryInfo = new DirectoryInfo("C:/YOUR/DIRECTORY/HERE]");
var files = directoryInfo.GetFiles("*.jpg").OrderBy(x => x.CreationTimeUtc);
foreach (var file in files)
{
//Your processing
}
Note this will get all the .jpg files in a directory. The foreach loop will start with the oldest files first.
This should get all the files in a directory:
private List<FileInfo> GetFileInfo()
{
string path = #"C:\MyPath";
List<FileInfo> files = new List<FileInfo>();
DirectoryInfo di = new DirectoryInfo(path);
//TopDirectoryOnly if you don't want subfolders
foreach (FileInfo f in di.GetFiles("*.jpg", SearchOption.TopDirectoryOnly))
{
files.Add(f);
}
return files;
}
Then in your code, iterate over the returned collection and do whatever work you need to do with them.
Related
I am trying to detect when a file is being removed from a folder in my drive. Upon detection, I want to write code that does something. Is there an event handler for this kind of 'event' in C#? Looked around but couldn't find any. Is it even possible?
You can use FileSystemWatcher to monitor a directory, and subscribe to it's Deleted event. See the code below
static void Main(string[] args)
{
FileSystemWatcher watcher = new FileSystemWatcher();
watcher.Path = "C:/some/directory/to/watch";
watcher.NotifyFilter = NotifyFilters.LastAccess |
NotifyFilters.LastWrite |
NotifyFilters.FileName |
NotifyFilters.DirectoryName;
watcher.Filter = "*.*";
watcher.Deleted += new FileSystemEventHandler(OnDeleted);
watcher.EnableRaisingEvents = true;
}
private static void OnDeleted(object sender, FileSystemEventArgs e)
{
throw new NotImplementedException();
}
I have a console app that need to monitor a specific directory and wait for all files to be deleted for a specific amount of time.
If after that time has exceeded and all of the files has not been deleted yet, I need the program to throw an exception. How can I accomplish this?
public static void FileWatcher(string fileName, int timeToWatch)
{
FileSystemWatcher watcher = new FileSystemWatcher();
try
{
watcher.Path = myPath;
watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.DirectoryName;
watcher.Filter = string.Format("*{0}*", fileName);
watcher.Deleted += new FileSystemEventHandler(OnChanged);
watcher.EnableRaisingEvents = true;
}
catch
{
throw;
}
}
You can use Task.Delay to setup a timeout (I assume timeToWatch is in milliseconds, if not then change it accordingly). If the directory has no more files (not checking subfolders) then it sets the other task as completed. The method will block (WaitAny) until either the timeout occurs or the files are all deleted. This can easily be changed to be async if required.
public static void FileWatcher(string fileName, int timeToWatch)
{
FileSystemWatcher watcher = new FileSystemWatcher();
var timeout = Task.Delay(timeToWatch);
var completedTcs = new TaskCompletionSource<bool>();
watcher.Path = myPath;
watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.DirectoryName;
watcher.Filter = string.Format("*{0}*", fileName);
watcher.Deleted += (s, e) => OnChanged(myPath, timeout, completedTcs);
watcher.EnableRaisingEvents = true;
OnChanged(myPath, timeout, completedTcs);
// Wait for either task to complete
var completed = Task.WaitAny(completedTcs.Task, timeout);
// Clean up
watcher.Dispose();
if (completed == 1)
{
// Timed out
throw new Exception("Files not deleted in time");
}
}
public static void OnChanged(string path, Task timeout, TaskCompletionSource<bool> completedTcs)
{
if (!Directory.GetFiles(path).Any())
{
// All files deleted (not recursive)
completedTcs.TrySetResult(true);
}
}
Below is my code, I am running a windows service, but if i kept ideal for long time 5 or 6 days after that it stops firing events. though my service is running.Please help me on this
private FileSystemWatcher watcher = new FileSystemWatcher();
public bool StartFileWatcher()
{
_logger.Info("StartFileWatcher File watcher started");
if (string.IsNullOrEmpty(_fileWatcherTargetPath))
{
_logger.Error("StartFileWatcher Directory name is null or Empty");
return false;
}
DirectoryInfo dir = new DirectoryInfo(_fileWatcherTargetPath);
if (!Directory.Exists(_fileWatcherTargetPath))
{
_logger.Info("StartFileWatcher Directory Created " + _fileWatcherTargetPath);
Directory.CreateDirectory(_fileWatcherTargetPath);
}
//Add folder path to file watcher
watcher.Path = _fileWatcherTargetPath;
watcher.IncludeSubdirectories = true;
//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;
// Add event handlers.
watcher.Created += new FileSystemEventHandler(OnChanged);
// Begin watching.
watcher.EnableRaisingEvents = true;
GC.KeepAlive(watcher);
SetTimer();
return true;
}
I am using FileSystemWatcher to monitor a folder that will be used to do some file renaming.
The only thing that will be copied will be folders containing files. There will not be single files put into the monitored folder. This is the code for setting up the FileSystemWatcher
watcher.Path = path;
watcher.NotifyFilter = NotifyFilters.DirectoryName | NotifyFilters.FileName;
watcher.IncludeSubdirectories = true;
watcher.Filter = "*.*";
watcher.Created += new FileSystemEventHandler(watcher_Created);
watcher.Changed += new FileSystemEventHandler(watcher_Changed);
watcher.Renamed += new RenamedEventHandler(watcher_Renamed);
watcher.EnableRaisingEvents = true;
There doesn't seem to be any issues with this setup..
The folders being copied can be between 50-200mb big. Is there a way to check/make sure that all the files have completed copying before starting the renaming process.
I tried this thinking that i would get an IOException if the copying was still happening when the GetFiles() was called.
bool finishedCopying = false;
while (!finishedCopying)
{
try
{
List<FileInfo> fileList = directoryInfo.GetFiles().ToList();
AlbumSearch newAlbum = new AlbumSearch(directoryInfo);
return newAlbum;
}
catch (IOException)
{
finishedCopying = false;
}
}
If anymore information is required, just ask an i can provide.
Ta.
I gave this a go using a timer. It may not be the prettiest solution out there but at first testing it seems to be working so far. Essentially what this does is when a folder is copied to the monitored folder it will add the folder path to the AlbumList. The files in that folder will trigger the Created event. This waits for the file to finish copying. Once finished it starts a timer. If a new Created event gets triggered the timer will reset itself.
When the timer.elapsed event is triggered it assumes (and I know assumption is the mother of all f*&k ups) that there are no more files to be copied and can start to process the fully copied folder..
System.Timers.Timer eventTimer = new System.Timers.Timer();
List<string> AlbumList = new List<string>();
private void watcher_Created(object sender, FileSystemEventArgs e)
{
if (Directory.Exists(e.FullPath))
{
AlbumList.Add(e.FullPath);
}
if (File.Exists(e.FullPath))
{
eventTimer.Stop();
FileInfo newTrack = new FileInfo(e.FullPath);
while (IsFileLocked(newTrack))
{
// File is locked. Do Nothing..
}
eventTimer.Start();
}
}
private void eventTimer_Elapsed(object sender, ElapsedEventArgs e)
{
List<string> ItemToRemove = new List<string>();
foreach (var item in AlbumList)
{
DirectoryInfo di = new DirectoryInfo(item);
AlbumSearch newAlbum = new AlbumSearch(di);
if (DoSomethingMethod(newAlbum))
{
ItemToRemove.Add(item);
}
else
{
// why did it fail
}
}
foreach (var path in ItemToRemove)
{
AlbumList.Remove(path);
}
}
private bool DoSomethingMethod(AlbumSearch as)
{
// Do stuff here
return true;
}
This is a small demo app that check files at the beginning, and then uses two hashsets to track copied files. This will only work if the source directory is known. There is no way to know if a file was created from a file copy or from a direct creation, so you can only compare two known directories with Directory.GetFiles. And, as already said in comments, you will still have to check if during the copy process, other files were added / removed / renamed in the old directory
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
class Program
{
static HashSet<string> oldDirFiles = new HashSet<string>();
static HashSet<string> newDirFiles = new HashSet<string>();
static string oldDir = "C:\\New Folder";
static string newDir = "C:\\New Folder 2";
static System.Threading.ManualResetEvent resetEvent = new System.Threading.ManualResetEvent(false);
static void Main(string[] args)
{
System.IO.FileSystemWatcher watcher = new System.IO.FileSystemWatcher();
watcher.Path = newDir;
watcher.NotifyFilter = NotifyFilters.DirectoryName | NotifyFilters.FileName;
watcher.IncludeSubdirectories = true;
watcher.Filter = "*.*";
watcher.Created += watcher_Created;
watcher.Changed += watcher_Changed;
watcher.Renamed += watcher_Renamed;
watcher.EnableRaisingEvents = true;
//get all files in old directory
var oldFiles = Directory.GetFiles(oldDir, "*.*", SearchOption.AllDirectories);
foreach (var file in oldFiles)
oldDirFiles.Add(file);
resetEvent.WaitOne();
//now launch the directory copy
//then you have to check if in the meaning time, new files were added or renamed
//that could be done also with a watcher in the old directory
}
static void watcher_Renamed(object sender, RenamedEventArgs e)
{
throw new NotImplementedException();
}
static void watcher_Changed(object sender, FileSystemEventArgs e)
{
throw new NotImplementedException();
}
static void watcher_Created(object sender, FileSystemEventArgs e)
{
//check if the copied file was in the old directory before starting
if (oldDirFiles.Contains(e.FullPath.Replace(newDir, oldDir)))
{
newDirFiles.Add(e.FullPath);
//if all the files have been copied, the file count will be the same in the two hashsets
//the resetevent.Set() signal the waiting thread and the program can proceed
if (newDirFiles.Count == oldDirFiles.Count)
resetEvent.Set();
}
}
}
}
I wrote program and need my own file watcher (loop that checks if file can be opened). Something like this:
while (loadedFiles.Count > 0 || isNeedReRead)
{
Thread.Sleep(1000);
if (isNeedReRead)
ReadFromRegistry();
foreach (var file in loadedFiles)
{
if (!IsFileLocked(file.Value))
{
// logic
}
}
}
Source: Is there a way to check if a file is in use?
Here is my solution:
try
{
using (Stream stream = new FileStream(
path, FileMode.Open, FileAccess.ReadWrite, FileShare.None))
{
stream.Close();
return false;
}
}
catch (IOException)
{
return true;
}
It works fine with Word, Excel. But if the process does not lock the file, this method doesn't help. For example if an open bitmap file is changing, IsFileLocked returns false.
Any ideas?
You can setup monitoring the file by using the System.IO.FileSystemWatcher you should be able to use that the NotifyFilter property (set to LastAccessTime) to detect when a particular file was last accessed.
void SetupWatcher()
{
// Create a new FileSystemWatcher and set its properties.
FileSystemWatcher watcher = new FileSystemWatcher();
watcher.Path = #"C:\";
/* Watch for changes in LastAccess and LastWrite times, and
the renaming of files or directories. */
watcher.NotifyFilter = NotifyFilters.LastAccess;
// 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);
// 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);
}
private static void OnRenamed(object source, RenamedEventArgs e)
{
// Specify what is done when a file is renamed.
Console.WriteLine("File: {0} renamed to {1}", e.OldFullPath, e.FullPath);
}
Another option assuming this is windows is to enumerate the list of open file handles for each process. The code posted here has a decent implementation so all you have to do is call
DetectOpenFiles.GetOpenFilesEnumerator(processID);
However, if a process opens a file reads the contents into memory then closes the file, you will be stuck with the monitoring option (listed above), since the process does not actually have the file open any longer once it is read into memory.