Please, explain your thoughts.
1. DateTime dt = System.IO.File.GetLastAccessTime("C:\\There_is_no_such_file.txt");
2. DateTime dt = System.IO.File.GetLastAccessTime("");
If the file described in the path parameter does not exist, this method returns 12:00 midnight, January 1, 1601 A.D. (C.E.) Coordinated Universal Time (UTC), adjusted to local time.
In the second situation argument exception is thrown.
Why in first case FileNotFoundException (or smth. simmilar) is not thrown?
Well, I didn't write any of the
System.IO
library, so I can't claim to have the answer to what exceptions are thrown at what point. What qualifies as an exception will always be a decision for the developer to take.I can take a stab at the reasoning behind this, though.
Having a file that doesn't exist may in a lot of cases be expected behavior. Having to hit the file system just to query whether a file exists, and then hit it again to get the access time for that file, might just have seemed like overhead, compared to simply hitting the file system once and verifying the result. If
DateTime
was nullable, this would probably have yieldednull
, just as one can imagine thatIndexOf
would have, instead of-1
.In the second case, however, passing an invalid path is evidence that somewhere in your code, something is maknig an expectation about something that cannot possibly work, and it might arguably make sense to bring this to the attention of the developer, by means of throwing an exception.
This is documented behavior. From the Remarks section in the MSDN Library topic:
If the file described in the path parameter does not exist, this method returns 12:00 midnight, January 1, 1601 A.D. (C.E.) Coordinated Universal Time (UTC), adjusted to local time.
The exception you get when you pass an empty string is one that's generated by code that checks if the passed string is a valid path name. Which is fair, that would be bug in the program.
The code is explicit so it wasn't done by oversight or by mistake. It uses the FindFirstFile() API function to locate the file. If that fails, it checks the Windows error. And explicitly ignores, the "File not found", "Path not found" and "Drive busy" errors.
Beware that offered solutions that use File.Exists don't actually prevent this problem. Windows is a multi-tasking operating system. Your thread may be pre-empted right after the Exists call and another process may delete the file. When your thread regains the CPU, you'll still get the bogus date.
The only guaranteed way to get an accurate date is to open the file first so that nobody can delete the file from under you. Which I think explains why the method behaves like it does. The framework designers were stuck between a rock and a hard place. If they would have opened the file first, they would have risked other programs bombing on a file sharing error. If they don't open the file first, they risk your program bombing randomly and infrequently. Extremely hard to diagnose. Having to choose between two unpleasant options, they chose the one that doesn't bomb anything.
Anyhoo, make it reliable by opening the file.
We're dealing with two different things.
When you call a method with an invalid argument, it should throw an exception.
If the file doesn't exist, this is not necessarily an exception. Therefore, a default value is returned, which you can test and decide how to proceed. For the GetLastAccessTime method, it isn't critical that the file exists. If it is critical for YOUR code, then you should be responsible for generating an error...
If you ask the question "When was the last time, the file "There_is_no_such_file.txt" was accessed?", you could either answer "There is no such file" or "never".
Obviously, the team that designed the IO library opted for the second answer, with never being represented as
DateTime.MinValue
.The reason might be that you have turned off the "Enable unmanaged code debugging option" check in project properties under the Debug section.
i believe its by design
12:00 midnight, January 1, 1601 A.D. (C.E.) is the minium date value, some people consider it as a no value, but that was after the nullable types