C# 在文件可用时立即移动文件

发布于 2024-08-30 22:51:31 字数 363 浏览 4 评论 0原文

我需要完成以下任务:

尝试移动文件。如果文件被锁定,则计划在其可用后立即移动。

我正在使用 File.Move 这对于我的程序来说已经足够了。现在的问题是:

1)我找不到一个好的方法来检查我需要移动的文件是否被锁定。我正在捕获 System.IO.IOException 但阅读周围的其他帖子我发现相同的异常也可能因不同的原因而引发。

2) 确定文件何时解锁。实现此目的的一种方法可能是使用计时器/线程并检查计划的文件(假设每 30 秒一次)并尝试移动它们。但我希望有更好的方法使用 FileSystemWatcher。

这是一个 .net 3.5 winforms 应用程序。如有任何意见/建议,我们将不胜感激。感谢您的关注。

I need to accomplish the following task:

Attempt to move a file. If file is locked schedule for moving as soon as it becomes available.

I am using File.Move which is sufficient for my program. Now the problems are that:

1) I can't find a good way to check if the file I need to move is locked. I am catching System.IO.IOException but reading other posts around I discovered that the same exception may be thrown for different reasons as well.

2) Determining when the file gets unlocked. One way of doing this is probably using a timer/thread and checking the scheduled files lets say every 30 seconds and attempting to move them. But I hope there is a better way using FileSystemWatcher.

This is a .net 3.5 winforms application. Any comments/suggestions are appreciated. Thanks for attention.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

病毒体 2024-09-06 22:51:31

您确实应该尝试捕获 IOException。使用 Marshal.GetHRForException 检查异常原因。
通知并不可靠。在执行 File.Move 之前,另一个进程可能会再次锁定文件。

You should really just try and catch an IOException. Use Marshal.GetHRForException to check for the cause of the exception.
A notification would not be reliable. Another process might lock the file again before File.Move is executed.

怼怹恏 2024-09-06 22:51:31

一种可能的替代方法是使用 MoveFileEx 带有 MOVEFILE_DELAY_UNTIL_REBOOT 标志。如果您现在无权移动该文件,则可以安排在下次重新启动时移动该文件,此时保证可以访问该文件(移动发生在启动序列的早期)。

根据您的特定应用程序,除了移动计划之外,您还可以通知用户需要重新启动并自行启动重新启动。

One possible alternative is by using MoveFileEx with a MOVEFILE_DELAY_UNTIL_REBOOT flag. If you don't have access to move the file right now, you can schedule it to be moved on the next reboot when it's guaranteed to be accessible (the moving happens very early in the boot sequence).

Depending on your specific application, you could inform the user a reboot is necessary and initiate the reboot yourself in addition to the moving scheduling.

画骨成沙 2024-09-06 22:51:31

很简单:

        static void Main(string[] args)
        {
            //* Create Watcher object.
            FileSystemWatcher watcher = new FileSystemWatcher(@"C:\MyFolder\");

            //* Assign event handler. 
            watcher.Created += new FileSystemEventHandler(watcher_Created);

            //* Start watching. 
            watcher.EnableRaisingEvents = true;

            Console.ReadLine();
        }


        static void watcher_Created(object sender, FileSystemEventArgs e)
        {
            try
            {
                File.Move(e.FullPath, @"C:\MyMovedFolder\" + e.Name);
            }
            catch (Exception)
            {
                //* Something went wrong. You can do additional proceesing here, like fire-up new thread for retry move procedure.
            }
        }

It's simple:

        static void Main(string[] args)
        {
            //* Create Watcher object.
            FileSystemWatcher watcher = new FileSystemWatcher(@"C:\MyFolder\");

            //* Assign event handler. 
            watcher.Created += new FileSystemEventHandler(watcher_Created);

            //* Start watching. 
            watcher.EnableRaisingEvents = true;

            Console.ReadLine();
        }


        static void watcher_Created(object sender, FileSystemEventArgs e)
        {
            try
            {
                File.Move(e.FullPath, @"C:\MyMovedFolder\" + e.Name);
            }
            catch (Exception)
            {
                //* Something went wrong. You can do additional proceesing here, like fire-up new thread for retry move procedure.
            }
        }
夜声 2024-09-06 22:51:31

这并不是特定于您的问题,但通常您始终需要为此类操作保留“尝试并优雅地处理失败”的操作模式。

这是因为,无论您的“检测文件可用”机制有多聪明,在您检测到文件可用和移动它之间总会有一段时间,在这段时间内其他人可能会弄乱文件。

This is not specific to your problem, but generally you will always need to retain the 'try it and gracefully deal with a failure' mode of operation for this sort of action.

That's because however clever your 'detect that the file is available' mechanism is, there will always be some amount of time between you detecting that the file is available and moving it, and in that time someone else might mess with the file.

猥琐帝 2024-09-06 22:51:31

计划的异常重试(可能会增加延迟 - 在一定程度上)可能是实现此目的的最简单方法(您的 (2) )。
为了正确地做到这一点,您将必须下降到系统级别(使用内核代码)挂钩来捕获文件关闭事件 - 该事件有其自己的特性。这是一项艰巨的工作 - 比计划的重试方法复杂几个数量级。这取决于您和您的应用程序案例来做出决定,但我不知道这之间有什么有效的方法。

The scheduled retry on exception (probably increasing delays - up to a point) is probably the simplest way to achieve this (your (2) ).
To do it properly you're going to have to drop to system level (with Kernel code) hooks to trap the file close event - which has its own idiosynchrases. It's a big job - several orders of magnitude more complex than the scheduled retry method. It's up to you and your application case to make that call, but I don't know of anything effective in between.

秋凉 2024-09-06 22:51:31

非常老的问题,但是谷歌引导我来到这里,所以当我找到更好的答案时,我决定发布它:

我发现了一个很好的代码 在 dotnet CLI 存储库中:

    /// <summary>
    /// Run Directory.Move and File.Move in Windows has a chance to get IOException with
    /// HResult 0x80070005 due to Indexer. But this error is transient.
    /// </summary>
    internal static void RetryOnMoveAccessFailure(Action action)
    {
        const int ERROR_HRESULT_ACCESS_DENIED = unchecked((int)0x80070005);
        int nextWaitTime = 10;
        int remainRetry = 10;

        while (true)
        {
            try
            {
                action();
                break;
            }
            catch (IOException e) when (e.HResult == ERROR_HRESULT_ACCESS_DENIED)
            {
                Thread.Sleep(nextWaitTime);
                nextWaitTime *= 2;
                remainRetry--;
                if (remainRetry == 0)
                {
                    throw;
                }
            }
        }
    }

还有一个仅针对 IOException 的方法。这是使用示例

FileAccessRetrier.RetryOnMoveAccessFailure(() => Directory.Move(packageDirectory.Value, tempPath));

总体而言,这个存储库包含许多关于文件操作和安装/删除逻辑的有趣想法,例如 TransactionalAction,因此我建议您查看它。不幸的是,这些函数不能作为 NuGet 包提供。

Very old question, but google led me here, so when I found a better answer I decided to post it:

There's a nice code I found in the dotnet CLI repo:

    /// <summary>
    /// Run Directory.Move and File.Move in Windows has a chance to get IOException with
    /// HResult 0x80070005 due to Indexer. But this error is transient.
    /// </summary>
    internal static void RetryOnMoveAccessFailure(Action action)
    {
        const int ERROR_HRESULT_ACCESS_DENIED = unchecked((int)0x80070005);
        int nextWaitTime = 10;
        int remainRetry = 10;

        while (true)
        {
            try
            {
                action();
                break;
            }
            catch (IOException e) when (e.HResult == ERROR_HRESULT_ACCESS_DENIED)
            {
                Thread.Sleep(nextWaitTime);
                nextWaitTime *= 2;
                remainRetry--;
                if (remainRetry == 0)
                {
                    throw;
                }
            }
        }
    }

There is also a method for just IOException. Here's the usage example:

FileAccessRetrier.RetryOnMoveAccessFailure(() => Directory.Move(packageDirectory.Value, tempPath));

Overall, this repo contains a lot of interesting ideas for file manipulations and installation/removal logic, like TransactionalAction, so I recommend it for reviewing. Unfortunately, these functions are not available as NuGet package.

断爱 2024-09-06 22:51:31

看一下 FileSystemWatcher。

http://msdn.microsoft.com /en-us/library/system.io.filesystemwatcher(VS.90).aspx

监听文件系统变化
通知并引发事件时
目录或目录中的文件,
变化

Have a look at the FileSystemWatcher.

http://msdn.microsoft.com/en-us/library/system.io.filesystemwatcher(VS.90).aspx

Listens to the file system change
notifications and raises events when a
directory, or file in a directory,
changes

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文