微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

完成创建后,监视文件夹并复制新文件

如何解决完成创建后,监视文件夹并复制新文件

我构建了一个控制台应用程序,该应用程序监视Windows 2019 Server上的一组文件夹,并使用相同的文件名将所有新创建的.txt文件复制到另一个文件夹中。到目前为止,它正在为基本功能工作。现在,我必须处理一个事实,在大多数情况下,这些文件很大,需要几分钟才能完成创建。我已经阅读了几篇SO文章,并拼凑了以下代码以实现此目的:

using System;
using System.IO;

namespace Folderwatch
{
    class Program
    {
        static void Main(string[] args)
        {
            string sourcePath = @"C:\Users\me\Documents\SomeFolder";

            FileSystemWatcher watcher = new FileSystemWatcher(sourcePath);

            watcher.EnableRaisingEvents = true;
            watcher.IncludeSubdirectories = true;
            watcher.Filter = "*.txt";

            // Add event handlers.
            watcher.Created += new FileSystemEventHandler(OnCreated);
        }

        // Define the event handlers. 

        private static void OnCreated(object source,FileSystemEventArgs e)
        {
            // Specify what is done when a file is created.
            FileInfo file = new FileInfo(e.FullPath);
            string wctPath = e.FullPath;
            string wctName = e.Name;
            string createdFile = Path.GetFileName(wctName);
            string destPath = @"C:\Users\SomeOtherFolder";
            string sourceFile = wctPath;
            string destFile = Path.Combine(destPath,createdFile);
            WaitForFile(file);
            File.copy(sourceFile,destFile,true);
        }

        public static bool IsFileLocked(FileInfo file)
        {
            try
            {
                using (FileStream stream = file.Open(FileMode.Open,FileAccess.Read,FileShare.None))
                {
                    stream.Close();
                }
            }
            catch (IOException)
            {
                //the file is unavailable because it is:
                //still being written to
                //or being processed by another thread
                //or does not exist (has already been processed)
                return true;
            }

            //file is not locked
            return false;
        }

        public static void WaitForFile(FileInfo filename)
        {
            //This will lock the execution until the file is ready
            //Todo: Add some logic to make it async and cancelable
            while (!IsFileLocked(filename)) { }
        }

    }
}

我要在OnCreated方法中执行的操作是检查并等待,直到文件创建完成,然后将文件复制到另一个目标位置。我似乎不知道我在WaitForFile(file)行中所做的工作-如果我注释掉该行并且文件创建是即时的,则文件将按预期进行复制。如果我使用WaitForFile行,则不会发生任何事情。我从SO的其他帖子中采用了IsFileLockedWaitForFile方法,但是显然我没有正确实现它们。

我已经注意到了这个Powershell版本Copy File On Creation (once complete),但我不确定这里的答案是否可以将我指向正确的方向b / c我对PS的了解甚至不如对C#的了解。

编辑#1:在接受答案之前,我应该进行更长时间的测试-我认为我们已经关闭了,但是在程序运行约一分钟后,在程序崩溃之前出现了以下错误

未处理的异常。 System.IO.IOException:进程无法访问 文件 'C:\ Users \ me \ DropBox \ test1.log' 因为它正在被另一个进程使用。在 System.IO.FileSystem.copyFile(String sourceFullPath,String destFullPath,布尔覆盖) Folderwatch.Program.OnCreated(对象源,FileSystemEventArgs e)在 C:\ Users \ me \ OneDrive- Development \ Source \ repos \ FolderWatchCG \ FolderWatchCG \ Program.cs:line 61在System.Threading.Tasks.Task。 c.b__139_1(Object 州) System.Threading.QueueUserWorkItemCallbackDefaultContext.Execute()
在System.Threading.ThreadPoolWorkQueue.dispatch()处 System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()

任何对此的建议将不胜感激。当我进一步分析这些文件夹中的文件时,其中一些是实时写入的日志文件,因此可能是在实际完成写入之前将其写入了几个小时。我想知道NotifyFilter之一是否在这里起作用?

解决方法

WaitForFile()方法中存在一个错误,即它当前正在等待文件 not 锁定时(反之亦然)。除此之外,您还需要一种方法来确认文件确实存在。一种简单的实现方法是将WaitForFile()方法更改为如下形式:

public static bool WaitForFile(FileInfo file)
{
    while (IsFileLocked(file))
    {
        // The file is inaccessible. Let's check if it exists.
        if (!file.Exists) return false;
    }

    // The file is accessible now.
    return true;
}

只要文件存在并且无法访问,它将一直等待。

然后,您可以按以下方式使用它:

bool fileAvailable = WaitForFile(file);
if (fileAvailable)
{
    File.Copy(sourceFile,destFile,true);
}

这种方法的问题是while循环使线程繁忙,这a)消耗了大量的CPU资源,b)阻止程序处理其他文件,直到完成等待那一个文件。因此,最好在每次检查之间使用异步等待。

WaitForFile方法更改为:

public static async Task<bool> WaitForFile(FileInfo file)
{
    while (IsFileLocked(file))
    {
        // The file is inaccessible. Let's check if it exists.
        if (!file.Exists) return false;
        await Task.Delay(100);
    }

    // The file is accessible now.
    return true;
}

然后在OnCreated内等待,像这样:

private async static void OnCreated(object source,FileSystemEventArgs e)
{
    // ...

    bool fileAvailable = await WaitForFile(file);
    if (fileAvailable)
    {
        File.Copy(sourceFile,true);
    }
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。