如何在后台 运行 时监视文件夹中的文件并将所述文件移动到另一个文件夹?

How to Monitor a Folder for files and move said files to another folder while running in background?

我想要一个持续监视文件夹中文件的程序,当文件出现在所述文件夹中时,程序应等待文件可访问,然后将所述文件移动到另一个文件夹。当前文件未从文件夹 "test" 移动到 "test2"。

我这样做是为了当我单击开始按钮时,表单会最小化并在后台运行,不断监视文件夹。

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);
                }
            }
        }

表面上看不明显,但实际情况是文件没有从文件夹 "test" 移动到文件夹 "test2",没有抛出异常,没有错误,文件没有被任何东西使用也没有打开,权限也都设置正确,文件很简单,没有被移动

编辑解决方案:由于此线程中发布的答案,代码现在可以工作了。 我自己添加了一些东西,以便处理重复的异常。

folderlocationpath 和 folderdestinationpath 变量是通过文件夹浏览器对话框读取的,因此用户可以自己选择 2 个文件夹位置 这是我目前拥有的:

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)));
                    }
            }

答案显而易见.. 您将文件夹路径传递给 File.Move 在文件输入和文件输出路径中。

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

在正文中添加了 1 个字符

我考虑过对@BanMe 的回答进行编辑,但似乎在回复中包含更多内容会更好,因为我会有效地为他建议的修复添加额外的更改(这,其实很重要)经过我自己的测试。

这已经过测试,验证可以在我的系统上工作。为了使它更有效地工作,我必须进行一项额外的更改。它包含对 Move 命令 Path.Combine 的修复,但更重要的是还向 FileName 添加了 NotifyFilter

您应该能够放置这部分代码,并且它应该按照我的测试预期的那样工作。

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)));
        }
    }
}

为什么我们需要扩展NotifyFilters?看看 this answer,我将在这里总结相关部分:

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!

您将 NotifyFilter 隔离为仅 LastWrite 似乎忽略了 FileSystemWatcher 的其他方面。添加 FileName 解决了我的问题。

如果文件已经存在于 C:\TEST2\ 文件夹中,您可能仍会遇到异常,但如果必须的话,这是在 File.Move 之前进行的非常简单的调整。