2010-06-04 17 views
13

Por favor, explique sus pensamientos.C#-¿Por qué System.IO.File.GetLastAccessTime devuelve un valor esperado cuando no se encuentra el archivo?

1. DateTime dt = System.IO.File.GetLastAccessTime("C:\\There_is_no_such_file.txt"); 
2. DateTime dt = System.IO.File.GetLastAccessTime(""); 
  1. Si no existe el archivo descrito en el parámetro de ruta, este método devuelve 12:00 de la noche, 1 de enero 1601 dC (C. E.) Tiempo Universal Coordinado (UTC), ajustado a la hora local.

  2. En el segundo argumento de situación se lanza una excepción.

¿Por qué en primer caso FileNotFoundException (o algo bajo. Simmilar) no sea despedida?

+0

Interesante. Me pregunto si alguien puede pensar en algún otro método en ese espacio de nombres que use el mismo patrón. –

+0

Interesante, marcado :) – RvdK

+2

Buena pregunta. Dudo que pueda haber una respuesta que no sea "esto es por diseño, tendrías que preguntarle a Microsoft" aunque ... – Daan

Respuesta

9

Se ha documentado el comportamiento. Desde la sección Observaciones en el tema Biblioteca MSDN:

Si el archivo descrito en el parámetro path no existe, este método devuelve 12:00 medianoche, 1 de enero de 1601 AD (CE) Hora Universal Coordinada (UTC), ajustado a la hora local.

La excepción que obtienes al pasar una cadena vacía es una que se genera mediante un código que comprueba si la cadena pasada es una ruta válida. Lo cual es justo, eso sería un error en el programa.

El código es explícito, por lo que no fue realizado por supervisión o por error. Utiliza la función API FindFirstFile() para localizar el archivo. Si eso falla, verifica el error de Windows. Y explícitamente ignora los errores "Archivo no encontrado", "Ruta no encontrada" y "Conducir ocupado".

Tenga en cuenta que las soluciones que se ofrecen que utilizan File.Exists en realidad no previenen este problema. Windows es un sistema operativo multitarea. Su cadena puede ser eliminada inmediatamente después de la llamada Existe y otro proceso puede eliminar el archivo. Cuando su hilo recupere la CPU, igual obtendrá la fecha falsa.

La única manera garantizada de obtener una fecha precisa es abrir primero el archivo para que nadie pueda eliminar el archivo debajo de usted. Lo que creo que explica por qué el método se comporta como lo hace. Los diseñadores del framework estaban atrapados entre una roca y un lugar duro. Si primero hubieran abierto el archivo, se habrían arriesgado a que otros programas bombardeen un error de intercambio de archivos. Si no abren el archivo primero, se arriesgan al bombardeo de su programa al azar y con poca frecuencia. Extremadamente difícil de diagnosticar. Al tener que elegir entre dos opciones desagradables, eligieron la que no bombardea nada.

Anyhoo, confírmelo mediante la apertura del archivo.

+0

Muy buena y clara descripción. Gracias. –

+1

Excelente respuesta, +10 si pudiera. – Codesleuth

+0

Información interesante. Sin embargo, aunque la respuesta describe la mecánica, no creo que explique la decisión de diseño de no arrojar 'FileNotFoundException' cuando no se encuentra el archivo. Después de la llamada a 'FindFirstFile', * es un hecho conocido para el código si el archivo (o la ruta) no existe *, y no hay ningún problema de bloqueo (por lo que puedo ver) ya que no hay ningún archivo. Así que todavía no entiendo el razonamiento de no lanzar una excepción en ese caso particular (como lo hace con 'File.GetAttributes'). –

0

creo que es por diseño

12:00 de la noche, 1 de enero 1601 ANUNCIO (CE) es el valor de fecha minio, algunas personas lo consideran como un valor, pero eso fue después de que los tipos anulables

+3

Sí, pero la pregunta era ¿por qué? –

2

Estamos lidiando con dos cosas diferentes.

Cuando llama a un método con un argumento no válido, debe lanzar una excepción.

Si el archivo no existe, esto no es necesariamente una excepción. Por lo tanto, se devuelve un valor predeterminado, que puede probar y decidir cómo proceder. Para el método GetLastAccessTime, no es crítico que el archivo exista. Si es imprescindible para su código, entonces debería ser responsable de generar un error ...

if (!File.Exists("C:\\There_is_no_such_file.txt")) { 
    throw new FileNotFoundException(); 
} 
+1

Naturalmente, habría comprobado la existencia del archivo antes de llamar a GetLastAccessTime de todos modos. Este comportamiento parece extraño. –

+0

@David Neale: considere la seguridad de las cadenas de caracteres como lo mencionó Donal Fellows en el comentario de mi respuesta. considere que tiene una solución en la que un archivo no existente es el comportamiento esperado, pero si hay un archivo, desea conocer su tiempo de acceso, y desea que este sea seguro para subprocesos. ¡tendrías que replicar para intentar/atrapar! Si podemos suponer que la afirmación de que "este archivo existe y se tuvo acceso a fines del renacimiento" es una falta de sentido, entonces esta es una forma informativa de hacerlo. –

+0

... al igual que '" abc ".indexOf (" d ")' podría decirse que "la cadena 'abc' contiene 'd', en la posición -1" solo así no interpretamos el resultado.si estos tipos fueran anulables, entonces nulo sería la respuesta omnipresente al rendimiento en estos escenarios. pero ni int ni datetime es ... –

0

La razón podría ser que se haya apagado la "opción de depuración de código no administrado Habilitar" cheque en las propiedades del proyecto en el marco del Sección de depuración

+1

Esta pregunta no llama a ningún código no administrado. –

+0

Por supuesto que es pero no explícitamente. – Wodzu

1

Bueno, no escribió ninguna de la biblioteca System.IO, por lo que no puede pretender tener la respuesta a lo que se lanzan excepciones en qué momento. Lo que califica como una excepción siempre será una decisión que debe tomar el desarrollador.

Sin embargo, puedo dar un vistazo al razonamiento detrás de esto.

Tener un archivo que no existe puede ser en muchos casos el comportamiento esperado. Tener que presionar el sistema de archivos solo para consultar si existe un archivo, y luego presionarlo nuevamente para obtener el tiempo de acceso para ese archivo, podría haber parecido una sobrecarga, comparado con simplemente presionar el sistema de archivos una vez y verificar el resultado. Si DateTime fue anulable, esto probablemente habría dado null, tal como se puede imaginar que IndexOf tendría, en lugar de -1.

En el segundo caso, sin embargo, el paso de una ruta no válida es evidencia de que alguna parte de su código, algo está maknig una expectativa de algo que no posiblemente puede funcionar, y que posiblemente podría tener sentido para llevar esto a la atención de el desarrollador, mediante el lanzamiento de una excepción.

+0

Por supuesto, si lanzó una excepción en cualquier archivo inexistente, lo correcto sería manejar la excepción en lugar de tratar de vencer una condición de carrera (entre el código que lee el tiempo de acceso y otro proceso que intenta eliminar el archivo). –

+0

@Donal Fellows: bueno, sí, supongo que es correcto, pero incluso esa sería una triste manera de tener que responder. un archivo inexistente puede incluso ser el * escenario más común * en algunos casos, y tener que tratar ese comportamiento esperado mediante la captura de prueba y la excepción sería un diseño deficiente. Supongo que esta línea de razonamiento es exactamente lo que conduce al diseño actual. –

+0

Creo que no estoy de acuerdo. Uno de los problemas perniciosos en la programación de C, especialmente cuando se hace interfaz con el sistema operativo, es no verificar los casos de error donde se devuelven valores de señal especiales. Demasiados programadores simplemente no hacen eso en la naturaleza, o al menos no hasta que se hayan quemado gravemente. Las excepciones ayudan mucho asegurando que el código trate explícitamente las cosas (o al menos haya una política deliberada para ignorar los problemas). –

1

Si hace la pregunta "¿Cuándo fue la última vez que se accedió al archivo" There_is_no_such_file.txt "?, Puede responder" No existe tal archivo "o" nunca ".

Obviamente, el equipo que diseñó la biblioteca IO optó por la segunda respuesta, y nunca se representó como DateTime.MinValue.

Cuestiones relacionadas