Безопасное копирование файлов на NAS Filer

у нас есть файл NetApp NAS, который время от времени, кажется, терпит неудачу, не уверен, зависит ли это от сетевых проблем, большой нагрузки или самого файла; дело в том, что обычный System.IO.File.Copy(...) команда иногда неожиданно терпит неудачу, когда она работала за минуту до и работает снова через минуту... filer работает с файловой системой CIFS.

в моих лог-файлах Log4Net я вижу исключение:

Система.ИО.IOException: указанное сетевое имя больше не доступный. в системе.IO.__Ошибка.WinIOError (код ошибки Int32, строка maybeFullPath) ...

сетевая команда не уверена, что происходит и почему, я теперь думаю, если я могу реализовать простую систему try/retry для копирования файла и повторной попытки копирования в случае сбоя, это может быть эта система.ИО.Файл.Копирование не предназначено для хранилищ CIFS, а для обычных NTFS-дисков или стабильного сетевого хранилища.

существуют ли общие шаблоны или классы .NET, подходящие для этого скопировать и повторить или я должен просто использовать подход как в следующие псевдо-код?

while(!copied && count <5)
{
  count++;

  try
  {
    //here copy the file
    ...

    //if no exception copy was ok
    copied = true;
  }
  catch
  {
    if(count >= 5)
    {
      // Log that retry limit has been reached...
    }
    else
    {
      // make thread to wait for some time,
      // waiting time can be in function of count or fixed...
    }
  }
} 

2 ответов


же случится со мной. У меня старый сервер NAS и время от времени Windows показывает ошибку, сообщающую мне, что диск больше не доступен.
Управление процесс копирования файлов может быть, вы могли бы вместо этого использовать CopyFileEx (от Windows API), как показано в следующем примере:

public class SecureFileCopy
{
    public static void CopyFile(FileInfo source, FileInfo destination, 
        CopyFileOptions options, CopyFileCallback callback, object state)
    {
        if (source == null) throw new ArgumentNullException("source");
        if (destination == null) 
            throw new ArgumentNullException("destination");
        if ((options & ~CopyFileOptions.All) != 0) 
            throw new ArgumentOutOfRangeException("options");

        new FileIOPermission(
            FileIOPermissionAccess.Read, source.FullName).Demand();
        new FileIOPermission(
            FileIOPermissionAccess.Write, destination.FullName).Demand();

        CopyProgressRoutine cpr = callback == null ? 
            null : new CopyProgressRoutine(new CopyProgressData(
                source, destination, callback, state).CallbackHandler);

        bool cancel = false;
        if (!CopyFileEx(source.FullName, destination.FullName, cpr, 
            IntPtr.Zero, ref cancel, (int)options))
        {
            throw new IOException(new Win32Exception().Message);
        }
    }

    private class CopyProgressData
    {
        private FileInfo _source = null;
        private FileInfo _destination = null;
        private CopyFileCallback _callback = null;
        private object _state = null;

        public CopyProgressData(FileInfo source, FileInfo destination, 
            CopyFileCallback callback, object state)
        {
            _source = source; 
            _destination = destination;
            _callback = callback;
            _state = state;
        }

        public int CallbackHandler(
            long totalFileSize, long totalBytesTransferred, 
            long streamSize, long streamBytesTransferred, 
            int streamNumber, int callbackReason,
            IntPtr sourceFile, IntPtr destinationFile, IntPtr data)
        {
            return (int)_callback(_source, _destination, _state, 
                totalFileSize, totalBytesTransferred);
        }
    }

    private delegate int CopyProgressRoutine(
        long totalFileSize, long TotalBytesTransferred, long streamSize, 
        long streamBytesTransferred, int streamNumber, int callbackReason,
        IntPtr sourceFile, IntPtr destinationFile, IntPtr data);

    [SuppressUnmanagedCodeSecurity]
    [DllImport("Kernel32.dll", CharSet=CharSet.Auto, SetLastError=true)]
    private static extern bool CopyFileEx(
        string lpExistingFileName, string lpNewFileName,
        CopyProgressRoutine lpProgressRoutine,
        IntPtr lpData, ref bool pbCancel, int dwCopyFlags);
}

public delegate CopyFileCallbackAction CopyFileCallback(
    FileInfo source, FileInfo destination, object state, 
    long totalFileSize, long totalBytesTransferred);

public enum CopyFileCallbackAction
{
    Continue = 0,
    Cancel = 1,
    Stop = 2,
    Quiet = 3
}

[Flags]
public enum CopyFileOptions
{
    None = 0x0,
    FailIfDestinationExists = 0x1,
    Restartable = 0x2,
    AllowDecryptedDestination = 0x8,
    All = FailIfDestinationExists | Restartable | AllowDecryptedDestination
}

здесь более подробное описание в журнале MSDN.


после недель и недель исследований, тестов и боли я, наконец, нашел рабочее решение, решил заменить System.IO.File.Copy метод с вызовом команда Microsoft Robocopy который доступен в Win Server 2008 R2 и, казалось, хорошо работает с первой попытки. Это делает меня комфортным, что я не изобретаю колесо, а использую испытанную технологию, разработанную именно для моих нужд. спасибо всем за ваши ответы и комментарии в любом случае.