-3

I want a program that will constantly monitor a folder for files, when a file appears in said folder the program should wait for the file to be accessible and then move said file to another folder. Currently the files are not being moved from folder "test" to "test2".

I made it so that when i click the start button the form is minimized and runs in background constantly monitoring the folder.

private void btstart_Click(object sender, EventArgs e)
        {
            this.WindowState = FormWindowState.Minimized;

            FileSystemWatcher watcher = new FileSystemWatcher();
            watcher.Path = @"C:\test";
            watcher.NotifyFilter = NotifyFilters.LastWrite;



            watcher.Created += new FileSystemEventHandler(watcher_FileCreated);
            watcher.EnableRaisingEvents = true;
        }

        public static bool Ready(string filename)
        {
            try
            {
                using (FileStream inputStream = File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.None))
                    return inputStream.Length > 0;
            }
            catch (Exception)
            {
                return false;
            }
        }
        void watcher_FileCreated(object sender, FileSystemEventArgs e)
        {
            string path1 = @"C:\test";
            string path2 = @"C:\test2";
            string files = @"*.*"; 
            string[] fileList = Directory.GetFiles(path1, files);
            foreach (string file in fileList)
            {
                if (Ready(file) == true)
                {
                    File.Move(path1, path2);
                }
            }
        }

Apperently it is not obvious, but what is happening is that the file is not moved from folder "test" to folder "test2", there is no exception thrown, there are no errors, the file is not in use by anything nor is it open, permissions are all set correctly aswell, the file is simple not being moved

EDIT SOLUTION : The code works now thanks to the answer posted in this thread. Ive added a couple of things myself so that a duplicate exception will be handled.

folderlocationpath & folderdestinationpath variables are read through a folderbrowserdialog, so that user can choose the 2 folder locations himself This is what i currently have :

string path1 = folderlocationpath;
            string path2 = folderdestinationpath;
            string files = @"*.*";
            string[] fileList = Directory.GetFiles(path1, files);
            foreach (string file in fileList)
            {
                if (Ready(file) == true)
                    try
                    {
                        File.Move(file, Path.Combine(path2, Path.GetFileName(file)));
                    }
                    catch (IOException) // for duplicate files an exception that deletes the file in destination folder and then moves the file from origin folder
                    {
                        string files2 = Path.GetFileName(file);
                        string[] fileList2 = Directory.GetFiles(path2, files2);
                        foreach (string file2 in fileList2)
                            File.Delete(file2);

                        File.Move(file, Path.Combine(path2, Path.GetFileName(file)));
                    }
            }
John Linaer
  • 15
  • 1
  • 6
  • 4
    _"It just doesnt"_ - read [ask] and debug your code, [edit] your question to include the actual observed behavior. Most likely the files are still in use, and your code throws an exception - which you ignore. – CodeCaster Jan 22 '19 at 15:00
  • 1
    So, have you tried debugging your application? – Peter Bons Jan 22 '19 at 15:03
  • by "nothing happens" i thought it was obvious to assume that the file was just not being moved, and no it is not in use since i just have the file in the folder test sitting all this time there is no exception, there is no error, the file is simply not moving – John Linaer Jan 23 '19 at 07:11
  • 1
    No error? You are silently catching and ignoring exceptions! At a *minimum*, log something. –  Jan 24 '19 at 14:19
  • i tried to put a debug point at many positions and it just never raised the event to begin with but now it doesnt matter anymore since it works – John Linaer Feb 18 '19 at 14:53

2 Answers2

0

Answer is plain to see.. You pass Folder Path to File.Move in the file in and file out paths.

File.Move(file, path2 + "\" + System.IO.Path.GetFileName(file));

added 1 character in body

BanMe
  • 133
  • 1
  • 8
  • 2
    [Path.Combine](https://learn.microsoft.com/en-us/dotnet/api/system.io.path.combine?view=netframework-4.7.2) is the preferred way to create the full path name. – PaulF Jan 22 '19 at 15:25
  • doesnt work, the file that is in folder "test" is not being moved to folder "test2" no exceptions thrown and no errors, file is just not being moved – John Linaer Jan 23 '19 at 07:16
  • @JohnLinaer Either way, that particular line is also not correct. You're instructing the system to `Move` C:\TEST to C:\TEST2 - no specification of any filename at all (which would be `file` as it enumerates through the list of files collected). You'll also hit an exception if the files already exist in TEST2 and show up again in TEST at some point later on. – gravity Jan 23 '19 at 17:15
  • that does make sense, didnt even think about that, thanks for pointing out. but it still doesnt seem to be working, first of all the "\" is not allowed to be written directly, but even if i make a string a = @"\"; and put path2 + a + Path.GetFileName(file) it still doesnt move the files – John Linaer Jan 24 '19 at 07:29
  • 1
    String escape.. "\\". – BanMe Jan 24 '19 at 14:14
0

I considered writing an edit to @BanMe answer, but it seems like it would be better to be a bit more all-inclusive in the response, as I would effectively be adding an additional change to his suggested fix (which, in reality, is quite important) after testing on my own.

This has been tested, and is verified to work on my system. There was one additional changes that I had to make to get this to work more effectively. It incorporates the fix to the Move command, Path.Combine but more importantly adds a NotifyFilter to FileName as well.

You should be able to emplace this section of your code, and it should work as expected from my testing.

private void btstart_Click(object sender, EventArgs e)
{
    this.WindowState = FormWindowState.Minimized;
    FileSystemWatcher watcher = new FileSystemWatcher();
    watcher.Path = @"C:\test";
    watcher.NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.FileName;
    watcher.Created += new FileSystemEventHandler(watcher_FileCreated);
    watcher.EnableRaisingEvents = true;
}

public static bool Ready(string filename)
{
    try
    {
        using (FileStream inputStream = File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.None))
            return inputStream.Length > 0;
    }
    catch (Exception)
    {
        return false;
    }
}

void watcher_FileCreated(object sender, FileSystemEventArgs e)
{
    string path1 = @"C:\test";
    string path2 = @"C:\test2";
    string files = @"*.*";
    string[] fileList = Directory.GetFiles(path1, files);
    foreach (string file in fileList)
    {
        if (Ready(file) == true)
        {
            File.Move(file, Path.Combine(path2, System.IO.Path.GetFileName(file)));
        }
    }
}

Why do we need to expand the NotifyFilters? Take a look at this answer which I'll sum up the relevant portion here:

I've been having trouble with this behavior too. If you step through the code (and if you look at MSDN documenation, you'll find that NotifyFilter starts off with a default value of:

NotifyFilters.FileName | NotifyFilters.DirectoryName | NotifyFilters.LastWrite

So when you say .NotifyFilter = NotifyFilters.CreationTime, you're wiping out those other values, which explains the difference in behavior. I'm not sure why NotifyFilters.CreationTime is not catching the new file... seems like it should, shouldn't it!

It appears that your isolating the NotifyFilter to just LastWrite is ignoring other aspects of the FileSystemWatcher. Adding in FileName resolved the issue for me.

You may still hit an exception if the files exist in the C:\TEST2\ folder already, but that's a very simple adjustment to make prior to the File.Move if you have to.

gravity
  • 2,175
  • 2
  • 26
  • 34
  • One additional note: Due to the way you're filtering to get files, any file without an extension would never be moved at all. – gravity Jan 24 '19 at 17:56
  • 1
    Thanks alot for the help and explanation and sorry that i couldnt take a look at this earlier, had a bunch of other projects going. After testing for a while i found out that files are indeed being moved, but only if files are fed to the folder "test", while the program is running in background. However it seems that sometimes files just refuse to be moved after copied, happens like 1/3 times i feed it a file, i think i might be feeding it too fast and since it doesnt raise an event for files already being in the folder, it just moves it when i feed it another. – John Linaer Feb 18 '19 at 08:08
  • 1
    So what i done is simply copy the code from watcher_FileCreated method and put it before the FileSystemWatcher(), thus as soon as i click start for the program to run in background, it will first move files already in the folder and then start watching for new files created there. Now i just need to figure out how to make it replace a file if it finds a duplicate – John Linaer Feb 18 '19 at 08:09
  • Consider looking for __how to move a file if the destination already exists__ or writing a new question just discussing this if nothing fits your scenario. I will hint that `File.Exists` would be a good source to start, using an `if` and `File.Delete` in case the `if` fails. Please upvote as well if this worked for you. – gravity Feb 18 '19 at 13:56
  • i already edited the original post with a way that handles the case of duplicate files. Its not the best implementation but it works for somebody who barely knows how to code. I used it with an exception because i already worked with file.exists in another programm so i wanted to learn exceptions a bit better. As for upvoting, i already did upvote your answer, but since i dont have enought reputation anything that i upvote doesnt show/count. – John Linaer Feb 19 '19 at 07:28