【问题标题】:Best .NET way to move many files to and from various directories?将许多文件移入和移出各种目录的最佳 .NET 方法?
【发布时间】:2014-05-12 03:10:09
【问题描述】:

我创建了一个程序,可以将文件移入和移出各种目录。我遇到的一个问题是当您尝试移动文件并且其他一些程序仍在使用它时。你得到一个错误。留下它是没有选择的,所以我只能想着必须一遍又一遍地尝试移动它。这虽然减慢了整个程序的速度,所以我创建了一个新线程并让它处理问题文件并继续下一个。更大的问题是当你有太多这些问题文件并且程序现在有太多线程试图移动这些文件时,它只会因一些 kernel.dll 错误而崩溃。这是我用来移动文件的代码示例:

Public Sub MoveIt()
    Try
        File.Move(_FileName, _CopyToFileName)
    Catch ex As Exception
        Threading.Thread.Sleep(5000)
        MoveIt()
    End Try
End Sub

如您所见,我尝试移动文件,如果出错,我等待并一遍又一遍地移动它。我也尝试过使用FileInfo,但这比使用File 对象要快得多。

那么有没有人找到一种万无一失的方法来移动文件而不会出错?

注意:需要大量文件才能使其崩溃。周末会没事的,但到周一结束时,它就完成了。

更新

到目前为止,我很欣赏所有的想法。也许我应该提供更多关于我在做什么的信息。

这一切都在 Windows 服务中完成。必须移动文件。我没有办法留下任何东西。这就是为什么我必须一遍又一遍地尝试移动这些文件的原因。这些文件用于将数据导入各种数据库。另外,没有用户告诉文件是否无法移动。此外,该程序每天处理数千个文件。

这么说吧。我怎样才能有一个高效的程序,可以在没有任何用户交互的情况下移动文件,并保证所有文件都被移动?创建这些文件的程序最终会放弃对它们的控制。它们由 FTP、Biztalk 和其他各种服务创建。

【问题讨论】:

  • 我认为有更好的方法来做任何你想做的事情(在更高的层次上)。
  • 联系正在创建这些文件的应用程序的程序员。告诉他们您想要一种移动文件的方法,即使应用程序正在写入文件。确保你不接受NO!求答案!
  • 好吧,我怀疑我可以告诉微软.. 或各种 3rd 方 FTP 程序.. 如果有更好的方法来移动和排序文件.. 请告诉我你的想法..

标签: file filesystems .net


【解决方案1】:

为什么不创建一个需要移动的文件队列,因为您的服务发现要移动的新文件(假设它进行某种连续扫描,您没有提到这部分),您可以将它们添加到队列中,然后可以由第二个线程处理,该线程不断地从队列的头部获取文件并尝试移动它。如果由于文件被锁定而导致移动失败,只需将其重新插入队列的后面并继续。这样你只需要担心 2 个线程,如果文件最终被释放,那么一切都会好起来的。

我会考虑用它在队列中花费的时间和移动尝试次数标记每个文件,一旦达到某个阈值(例如无法移动 3 小时 / 20 次尝试),然后发送一封电子邮件提醒适当的人。

【讨论】:

  • 那行得通.. 对我的情况来说是最好的主意。谢谢!
  • 很高兴我能帮上忙!为这个以及人们花时间写的其他答案投赞成票可能是一个很好的姿态。
【解决方案2】:

Windows 不是 Unix,因此您不能指望能够移动打开的文件。如果它正在使用中,那么移动它是不可能的。除非打开文件的进程明确禁止这样做,否则您可以复制正在使用的文件。我不确定是否要为已打开以供写入的文件提供任何数据保证。我最好的猜测是你必须知道你所做的是否安全。例如,读取附加到的日志文件是安全的,但读取为随机访问打开的文件则不安全。

我的建议是列出您无法移动的文件,可选择复制那些您可以移动的文件,并让用户可以选择在某个时候手动重试失败的文件。

【讨论】:

  • 我更新了我的帖子。没有任何用户,必须移动所有文件。一个都不能落下。
【解决方案3】:

我可以提出一些改进建议:

  1. 使用循环而不是递归,这样就看不到这个网站的名称(堆栈溢出异常)
  2. 每次尝试后,您都应该向用户展示究竟是哪里出了问题。您可以检查一堆异常:SecurityException、UnauthorizedAccessException、FileNotFoundException、DirectoryNotFoundException 等。其中一些异常会在最坏的情况下无限运行您的循环,直到用户说停止尝试。
  3. 如果您的移动过程应该在没有用户交互的情况下运行,您可以创建一些规则来决定是否继续尝试。这些规则应基于您获得的异常类型。

【讨论】:

  • 我在帖子中添加了更新。我可以尝试使用循环,没有用户可以显示,我必须移动每个文件。不能留下任何文件。
  • 您可以尝试将其拆分为 2 个线程:一个用于复制文件,一个用于删除文件。所以你应该继续跟踪哪些文件必须被删除和哪些被复制,但是这样你可以尝试不那么频繁地删除文件。
【解决方案4】:

您可以尝试使用 ThreadPool.QueueUserWorkItem 将工作排队,这可能会防止您的线程失控

【讨论】:

  • 这里只有一个线程,没看到QueueUserWorkItem的优势?
  • "这虽然减慢了整个程序的速度,所以我创建了一个新线程,让它处理问题文件并继续下一个。更大的问题是当你有太多这些问题时文件和程序现在有很多线程试图移动这些文件,它只是与一些 kernel.dll 崩溃“你特别说你有很多线程?
【解决方案5】:

就像@Morten 所说,您应该首先检查移动操作失败的原因,并尝试检测/通知用户,并做一些更聪明的事情然后重试。

关于您的代码:

您不应该从递归调用开始。如果一个文件长时间保持锁定,您的堆栈会变得越来越大,可能会出现 StackOverflowException,具体取决于它运行的时间和超时的实际值)。重试文件应该在循环内完成,如果在“N”次尝试后不成功,则会出错。类似的东西

Public Sub MoveIt()
    Dim succeeded as Boolean
    succeeded = False

    Dim numberOfTries as Integer
    numberOfTries = 0

    While Not succeeded And numberOfTries < 10 Then
        Try
            File.Move(_FileName, _CopyToFileName)
            succeeded = True
        Catch ex As Exception
            Threading.Thread.Sleep(5000)
            numberOfTries += 1
        End Try
    End While
End Sub

请注意,这样做时,需要 5 * 10 = 50 秒(!)才能发现文件确实无法移动,您仍然需要咨询用户。我认为以这种方式重试代码没有多大意义。

【讨论】:

  • 没有用户可以咨询。这是一个 Windows 服务。
猜你喜欢
  • 2021-12-05
  • 2022-01-20
  • 2011-05-09
  • 2012-09-02
  • 1970-01-01
  • 2018-01-08
  • 2011-02-14
  • 2011-01-30
  • 2012-09-03
相关资源
最近更新 更多