最好的.NET方式将许多文件移入和移出各种目录?

时间:2010-03-29 22:44:41

标签: file filesystems .net

我创建了一个程序,可以将文件移入和移出各种目录。我遇到的一个问题是当你试图移动文件而其他一些程序仍在使用它时。你得到一个错误。离开那里是没有选择的,所以我只能想到不得不继续尝试一遍又一遍地移动它。这虽然减慢了整个程序的速度,所以我创建了一个新的线程,让它处理问题文件并转到下一个。更大的问题是当你有太多这些问题文件并且程序现在有这么多线程试图移动这些文件时,它只是崩溃了一些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服务中完成。必须移动文件。我无法抛弃任何东西。这就是为什么我必须尝试OVER和OVER再次移动这些文件。这些文件用于将数据导入各种数据库。此外,没有用户可以判断文件是否无法移动。此外,该程序每天处理数千个文件。

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

5 个答案:

答案 0 :(得分:2)

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

我的建议是制作一个您无法移动的文件列表,可选择复制那些可以使用的文件,并为用户提供手动重试失败文件的选项。

答案 1 :(得分:2)

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

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

答案 2 :(得分:2)

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

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

答案 3 :(得分:0)

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

答案 4 :(得分:0)

就像@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秒(!)才能发现文件确实无法移动,您仍然需要咨询用户。我认为以这种方式重试代码并不重要。