2009-01-08 10 views
5

Tengo una aplicación C# y deseo copiar un archivo a una nueva ubicación. Algunas veces necesito sobrescribir un archivo existente. cuando esto sucede, recibo una System.IO.IOException. Deseo recuperarme de una violación de Compartir, pero ¿cómo puedo determinar que se haya devuelto IOException porque el archivo de destino está en uso en lugar de otro motivo? Podría buscar el "El proceso no puede acceder al archivo porque lo está usando otro proceso". mensaje ... Pero no me gusta esa idea.¿Cómo puedo determinar si se lanza una IOException debido a una infracción de uso compartido?

Respuesta

5

Este article explica cómo obtener la excepción HRESULT para que pueda determinar la causa del error.

+0

estaba a punto de mostrar que :) –

+0

No, IOException utiliza el COR_E_IO HRESULT que tiene la constante valor 0x80131620 [ver Clase IOException] (https://msdn.microsoft.com/en-us/library/system.io.ioexception (v = vs.110) .aspx). – tibx

+0

pero, de hecho, parece que la propiedad HResult de la clase IOException tiene el verdadero motivo de error HRSEULT ... – tibx

-1

Busque los códigos de error explícitos que se puede tratar, por ejemplo:

catch (Exception u) { if (((SocketException) u) .ErrorCode == 10035) ...

Echa un vistazo aquí: http://msdn.microsoft.com/en-us/library/ms681391(VS.85).aspx

de códigos de error, por ejemplo:

ERROR_SHARING_VIOLATION - 32 - 0x20

ERROR_ACCESS_DENIED = 5 - 0x5

ERROR_FILE_NOT_FOUND - 2 - 0x2

+0

¿Cómo se logrará el lanzamiento de IOException a SocketException? –

+0

solo un ejemplo ... no pensé que arrojaría a nadie – cookre

7

Esta fue la solución que se me ocurrió.

private void RobustMoveFile(System.IO.DirectoryInfo destinationDirectory, System.IO.FileInfo sourceFile, Boolean retryMove) 
       { 
        try 
        { 
         string DestinationFile = Path.Combine(destinationDirectory.FullName, sourceFile.Name); 
         if (File.Exists(DestinationFile)) 
          sourceFile.Replace(DestinationFile, DestinationFile + "Back", true); 
         else 
         { 
          sourceFile.CopyTo(DestinationFile, true); 
          sourceFile.Delete(); 
         } 
        } 
        catch (System.IO.IOException IOEx) 
        { 
         int HResult = System.Runtime.InteropServices.Marshal.GetHRForException(IOEx);   
         const int SharingViolation = 32; 
         if ((HResult & 0xFFFF) == SharingViolation && retryMove) 
          RobustMoveFile(destinationDirectory, sourceFile, false); 
         throw; 
        } 
       } 
+1

No es necesario verificar la existencia del archivo de destino, ya que otro proceso puede crearlo/eliminarlo entre las operaciones de verificación y reemplazo/Copiar a. Simplemente cambie su lógica de que siempre crea el archivo de detinación sin importar qué, y si esto falla, recupere o vuelva a intentarlo. –

1

Como han indicado otras respuestas, debe obtener el resultado HR del error y verificarlo. Un HResult de 32 es una violación de compartir.

En .NET 4.5, la IOException tiene un público HResult propiedad, por lo que sólo puede hacer lo siguiente:

try 
{ 
    // do file IO here 
} 
catch (IOException e) 
{ 
    if (e.HResult == 32) // 32 = Sharing violation 
    { 
     // Recovery logic goes here 
    } 
    else 
    { 
     throw; // didn't need to catch this 
    } 
} 

En versiones anteriores de .NET, sin embargo, es necesario obtener la HResult llamando Marshal.GetHRForException(Exception), por lo que el código similar sería:

try 
{ 
    // do file IO here 
} 
catch (IOException e) 
{ 
    int HResult = System.Runtime.InteropServices.Marshal.GetHRForException(e) 
    if (HResult == 32) // 32 = Sharing violation 
    { 
     // Recovery logic goes here 
    } 
    else 
    { 
     throw; // Or do whatever else here 
    } 
} 

el sin publicar C# 6.0 voluntad, según A C# 6.0 Language Preview, le permiten usar esta sintaxis para coger solamente un intercambio de violación:

try 
{ 
    // do file IO here 
} 
catch (IOException e) 
    if (e.HResult == 32) // 32 = Sharing violation 
{ 
    // Recovery logic goes here 
} 
+0

¿estás seguro de que esto es del todo correcto?experimentando con esto, creo que necesita bitwise y (&&) HResult con 0x000000000000FFFF. Entonces desea verificar (0xFFFF && e.HResult) == 32 – Greylander

+0

@Greylander Creo que tiene razón sobre el requisito de hacer el bitwise y, pero el operador es "&", no "&&". Este último es el cortocircuito lógico "y". BTW [aquí hay una referencia] (https://msdn.microsoft.com/en-us/library/ms680746.aspx) para convertir un error W32 a HRESULT. Por lo tanto, el propósito de la bit a bit es hacer lo contrario. – ricovox

Cuestiones relacionadas