Лучший способ .NET для перемещения многих файлов в и из различных каталогов? - PullRequest
1 голос
/ 30 марта 2010

Я создал программу, которая перемещает файлы в различные каталоги и обратно. Проблема, с которой я столкнулся, это когда вы пытаетесь переместить файл, а какая-то другая программа все еще использует его. И вы получаете ошибку. Оставить его там невозможно, поэтому я могу думать только о том, чтобы продолжать пытаться перемещать его снова и снова. Это, тем не менее, замедляет работу всей программы, поэтому я создаю новый поток, позволяю ему разобраться с файлом проблемы и перехожу к следующему. Большая проблема возникает, когда у вас слишком много этих проблемных файлов, и в программе теперь столько потоков пытается переместить эти файлы, что она просто вылетает с ошибкой 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.

Так кто-нибудь нашел надежный способ перемещения файлов без ошибок?

Примечание: для сбоя требуется много файлов. В выходные все будет хорошо, но к концу дня в понедельник все готово.

UPDATE

Я ценю все идеи до сих пор. Возможно, я должен дать больше информации о том, что я делаю.

Все это делается в службе Windows. Файлы ДОЛЖНЫ быть перемещены. Я никак не могу оставить позади. Вот почему я должен попробовать снова и снова, чтобы переместить эти файлы. Файлы используются для импорта данных в различные базы данных. Кроме того, нет НИКАКОГО пользователя, чтобы сказать, если файл не может быть перемещен. Также эта программа обрабатывает ТЫСЯЧИ файлов в день.

Так с этим сказал. Как я могу иметь эффективную программу, которая может перемещать файлы без какого-либо взаимодействия с пользователем и гарантировать, что все файлы будут перемещены? Программы, которые создают эти файлы, в конце концов перестают их использовать. Они создаются FTP, Biztalk и другими различными службами.

Ответы [ 5 ]

2 голосов
/ 30 марта 2010

Почему бы не создать очередь файлов, которые необходимо переместить, так как ваша служба обнаруживает новые файлы для перемещения (при условии, что выполняется какое-то непрерывное сканирование, вы не упомянули эту часть), вы можете добавить их в очередь , который затем может быть обработан вторым потоком, который постоянно извлекает файл из заголовка очереди и пытается переместить его. Если перемещение не удается из-за блокировки файла, просто вставьте его обратно в конец очереди и продолжите. Таким образом, вам нужно беспокоиться только о двух потоках, и если файлы все-таки будут выпущены, все должно быть хорошо.

Я бы посоветовал пометить каждый файл временем, которое он провел в очереди, и количеством попыток перемещения, и как только он достигнет определенного порога (например, неспособен переместиться в течение 3 часов / 20 попыток), затем отправить сообщение предупредить соответствующего человека.

2 голосов
/ 30 марта 2010

Есть несколько улучшений, которые я могу предложить:

  1. Используйте цикл вместо рекурсии, чтобы не видеть название этого сайта (исключение переполнения стека)
  2. После каждой попытки вы должны показывать пользователю, что именно не так. Существует множество исключений, которые вы можете проверить: SecurityException, UnauthorizedAccessException, FileNotFoundException, DirectoryNotFoundException и другие. Некоторые из этих исключений будут запускать ваш цикл бесконечно в худшем случае, пока пользователь не скажет прекратить попытки.
  3. Если ваш процесс перемещения должен выполняться без взаимодействия с пользователем, вы можете создать некоторые правила, чтобы решить, стоит ли продолжать попытки. Эти правила должны основываться на типе получаемого вами исключения.
2 голосов
/ 30 марта 2010

Windows не Unix, поэтому вы не можете ожидать, что сможете переместить открытый файл. Если он используется, то его перемещение невозможно. Вы можете, если процесс, открывающий файл, прямо не запретил это, копировать файлы, даже если они используются. Я не уверен, есть ли какие-либо гарантии данных для файлов, которые были открыты для записи. Я думаю, вы должны знать, безопасно ли то, что вы делаете. Например, чтение файла журнала, к которому добавляется файл, будет безопасным, но чтение файла, открытого для произвольного доступа, не будет.

Я бы порекомендовал составить список файлов, которые вы не смогли переместить, при желании скопировать те, которые вы можете, и дать пользователю возможность вручную повторить попытку сбойных файлов в определенный момент.

0 голосов
/ 30 марта 2010

Как сказал @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 секунд (!), Чтобы выяснить, что файл действительно не может быть перемещен, и вам все равно нужно проконсультироваться с пользователем. Я не думаю, что есть смысл повторять код таким образом.

0 голосов
/ 30 марта 2010

вы можете попробовать использовать ThreadPool.QueueUserWorkItem, чтобы поставить работу в очередь, что может помешать вашим потокам выйти из-под контроля

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...