Academic Integrity: tutoring, explanations, and feedback — we don’t complete graded work or submit on a student’s behalf.

I\'m wondering how better to perform this operation for a large amount of files.

ID: 644464 • Letter: I

Question

I'm wondering how better to perform this operation for a large amount of files. The bit I'd like some thoughts on whether this copy/paste is acceptable enough of a tradeoff.

try to write a file
if the target dir doesn't exist, create it
try again to write the file. If something else throws and exception, let it raise.
try{
   File.Copy("@D: oo.txt", @"C:mydir oo.txt");
}
catch (DirectoryNotFoundException){  
   CreateDirectoryForFile(@"C:mydir");
   File.Copy("@D: oo.txt", @"C:mydir oo.txt"); //copy pasted from the try block
}
There's a simpler block that's easier to read, but leads to a higher number of disk IO calls that is necessary:

CreateDirectoryForFile(@"C:mydir oo.txt");
File.Copy("@D: oo.txt", @"C:mydir oo.txt");
Can pattern 1 be improved?

Explanation / Answer

The simple principle is that this is not an Exception per se, it is an expected condition and thus should be checked using if (Directory.Exists(...)) to see if destination directory does not exist (and likewise if (File.Exists(...)) to check if the file already exists in that directory if that is important for your scenario).

You are paying a high performance price for this because exceptions are more costly. As an example, see that when you try to get an item from a Dictionary using an indexer, it throws a KeyNotFoundException if the item did not exist. To avoid having getting and catching this exception, usually people would first check the existence of the item using the Contains method and fetch it only if it existed. So, the Dictionary class thus provided a TryGetValue which will try to fetch the item, but if the item does not exist in the Dictionary, it just returns a false indicating so.

As DeadMG pointed out in the comments, there might be cases where concurrency works out better when you do not check and just perform the operation. An example could be that if your code was only creating the directory, it might be better to just use Directory.Create instead of first checking for existence because the file system state might change between the check and the actual operation.

A coding guideline that I use is that if a method allows one to check for a condition for which an exception may be thrown, consider using that method first, and only rely on exception if there is a strong reason not to check first. There are valid cases, especially over the network where if you checked for the existence of a file and then deleted it, it might incur high latency or bandwidth costs, in which case it might be preferable to just attempt an action and catch an exception. Azure Storage APIs, for example, use such an approach.

Avoid exceptions when a condition is one of the valid possibilities and there is no good reason to prefer exceptions. In your case, it is normal for the directory to not exist, and not an error condition, and you are dealing on the local disk.