2012-09-12 17 views
14

Al tratar de responder this question, me sorprendí al descubrir que intentar crear un nuevo archivo cuando ese archivo ya existe no arroja un tipo de excepción única, simplemente arroja un genérico IOException.Excepción códigos, o detección de un "archivo ya existe" tipo excepción

Por lo tanto, me pregunto cómo determinar si el IOException es el resultado de un archivo existente, o algún otro error de IO.

La excepción tiene HResult, pero esta propiedad está protegida y, por lo tanto, no está disponible para mí.

La única otra forma en que puedo ver es hacer coincidir el patrón con la cadena del mensaje, lo que se siente horrible.

ejemplo:

try 
{ 
    using (var stream = new FileStream("C:\\Test.txt", FileMode.CreateNew)) 
    using (var writer = new StreamWriter(stream)) 
    { 
     //write file 
    } 
} 
catch (IOException e) 
{ 
    //how do I know this is because a file exists? 
} 
+6

¿Por qué no acaba de comprobar para ver si existe el archivo? BESO. –

+3

Porque un sistema de archivos es inherentemente inestable. Los archivos se pueden crear en cualquier momento (no solo yo). – GazTheDestroyer

+1

Combinar errores múltiples en una excepción sin posibilidad de diferenciarlos es probablemente la peor característica del diseño de .NET framework. Tiene el mismo problema con el disco lleno, la ruta de red no encontrada, etc. IOExcepciones. Incluso si llega al código HResult, si su código también debe ejecutarse bajo Mono en Linux, eso no es compatible – jimvfr

Respuesta

7
try 
{ 
    using (var stream = new FileStream("C:\\Test.txt", FileMode.CreateNew)) 
    using (var writer = new StreamWriter(stream)) 
    { 
     //write file 
    } 
} 
catch (IOException e) 
{ 
    var exists = File.Exists(@"C:\Text.text"); // =) 
} 

no funcionará para los archivos temporales, etc., que podrían haber sido eliminados de nuevo.

+0

Durr, bastante obvio realmente, gracias! – GazTheDestroyer

+4

No es una forma determinista: el archivo podría eliminarse después de la excepción lanzada pero antes marcada en el bloque catch. – SerG

+1

Es por eso que dije 'No funcionará para archivos temporales, etc., que podría haber sido eliminado de nuevo' – jgauffin

0

Debe utilizar

FileMode.Create 

en lugar de

FileMode.CreateNew 

Se anulará un archivo si su ya existe.

+2

No quiero sobrescribir si existe – GazTheDestroyer

0

No puede. Desafortunadamente IOExceptions no se especifica más por alguna razón más allá de mi comprensión en el marco de .NET.

Pero en el caso de crear un archivo nuevo, es una práctica común verificar si el archivo existe primero. Como tal:

 try 
     { 
      if (File.Exists("C:\\Test.txt")) 
      { 
       //write file 

       using (var stream = new FileStream("C:\\Test.txt", FileMode.CreateNew)) 
       using (var writer = new StreamWriter(stream)) 
       { 
        //The actual writing of file 

       } 

      } 
     } 
     catch (IOException ex) 
     { 
      //how do I know this is because a file exists? 
      Debug.Print(ex.Message); 
     } 

Quizás no sea la respuesta que estabas buscando. Pero, c'est ca.

+0

El problema es: otro proceso * podría * crear el archivo entre la verificación de que existe y tratar de crearlo. Otra solución podría ser comprobar si el archivo existe * después de * la creación falla. –

+0

Es cierto. Buena llamada. –

0

No es 100% a prueba de tontos (hay otras razones para una IOException), pero al menos puede excluir todos los tipos de excepción derivados:

try 
{ 
    ... 
} 
catch(IOException e) 
{ 
    if (e is UnauthorizedAccessException) throw; 
    if (e is DirectoryNotFoundException) throw; 
    if (e is PathTooLongException) throw; 
    // etc for other exceptions derived from IOException 

    ... assume file exists 
} 

o el equivalente:

try 
{ 
    ... 
} 
catch(UnauthorizedAccessException) 
{ 
    throw; 
} 
catch(DirectoryNotFoundException) 
{ 
    throw; 
} 
catch(PathTooLongException) 
{ 
    throw; 
} 
catch(IOException e) 
{ 
    ... assume file exists 
} 

cuanto a la pregunta vinculada, solo verificaría la existencia, solicite al usuario que sobrescriba, luego use OpenOrCreate para sobrescribir si existe. Creo que la mayoría de las aplicaciones funcionan de esta manera, incluso si existe un riesgo teórico de sobrescribir un archivo creado en el momento incorrecto.

5

Puede colocar esta condición en su instrucción catch para IOException: if(ex.Message.Contains("already exists")) { ... }. Es un truco, pero funcionará para todos los casos en que exista un archivo, incluso archivos temporales y tal.

2

Para modificar @jgauffin, en C# 6, se puede utilizar el File.Exists en el interior de la cláusula when para evitar entrar en el bloque de catch y por lo tanto behaving more like an actual dedicated exception:

try 
{ 
    using (var stream = new FileStream("C:\\Test.txt", FileMode.CreateNew)) 
    using (var writer = new StreamWriter(stream)) 
    { 
     //write file 
    } 
} 
catch (IOException e) when (File.Exists(@"C:\Text.text")) 
{ 
    //... 
} 
2

Cuando intenta crear un nuevo archivo y se ya existe IOException tendrá Hresult = 0x80070050 (-2147024816).

Así que el código podría tener este aspecto:

try 
{ 
    using (var stream = new FileStream("C:\\Test.txt", FileMode.CreateNew)) 
    using (var writer = new StreamWriter(stream)) 
    { 
     //write file 
    } 
} 
catch (IOException e) 
{ 
    if (e.HResult == -2147024816) 
    { 
     // File already exists. 
    } 
} 
+0

HResult solía estar protegido (consulte mi tercer párrafo) por lo que esto solo parece ser válido en .Net4.5 en adelante, pero es útil saber que ahora está disponible, gracias. – GazTheDestroyer

Cuestiones relacionadas