3

Is it safe to delete or move files or directories when using Directory.EnumerateFiles?

Something like this:

foreach (var fileName in Directory.EnumerateFiles("Sub"))
    File.Delete(fileName);

I know that, in general, you are not supposed to modify what you're enumerating. However, the file system doesn't seem to be following that rule since the code above works.

The same question applies to EnumerateDirectories and EnumerateFileSystemEntries, as well as the equivalent methods of the DirectoryInfo class.

relatively_random
  • 4,505
  • 1
  • 26
  • 48
  • 3
    Related: [What happens with Directory.EnumerateFiles if directory content changes during iteration?](http://stackoverflow.com/questions/29555761/what-happens-with-directory-enumeratefiles-if-directory-content-changes-during-i) – stuartd Apr 07 '17 at 14:07
  • 1
    The rule you are talking about applies to modifying an underlying collection in a `foreach` because that will invalidate the`IEnumerator`. In this case the underlying data is not in a collection, but more like a stream of file names being delivered to you. Alternatively if you used `GetFiles` the underlying collection is an array, but you're not modifying that array with the deletes. – juharr Apr 07 '17 at 14:12
  • When ever deleting or moving object in a list while enumerating you must move through the list backwards for(i = length - 1, i >= 0, i--). The issue is when you remove an item the indexing get messed up. If you remove item 2, then item 3 becomes 2 and you end up skipping the origin item 3 in the enumerating. – jdweng Apr 07 '17 at 14:12
  • @jdweng But in this case it's not a list. – juharr Apr 07 '17 at 14:13
  • An enumerable object is a list : var fileName in Directory.EnumerateFiles("Sub").ToList() – jdweng Apr 07 '17 at 14:22

1 Answers1

2

Yes you can safely delete current file during such enumeration (at least on windows). Directory.EnumerateFiles is implemented internally (on windows) via FindFirstFile and FindNextFile winapi calls. So first FindFirstFile is called and on each iterator advance (MoveNext()) - FindNextFile is called. If file was removed between those calls - it's not a problem for that api, FindNextFile will just return next matching file. In your case you delete current file so that nothing is skipped at all. If new file were added in the middle of enumeration - it depends on it's name if it will be included or not. Say you already got files "b.txt" and "c.txt" and then file "a.txt" was added. Such file will not be included using Directory.EnumerateFiles, because it's name is "less" (in some sense) that files already enumerated. Return order is not that simple (depends on filesystem) but you got the idea.

Evk
  • 98,527
  • 8
  • 141
  • 191
  • Slightly unrelated: do you happen to know if GetFiles uses different API calls, meaning that it behaves slightly differently than EnumerateFiles? Or is their only difference that GetFiles enumerates all before returning? – relatively_random Apr 07 '17 at 14:31
  • 2
    @relatively_random yes GetFiles uses exactly the same api. Actually, `GetFiles` basically does `return EnumerateFiles(path).ToArray()`. Not literally, but they end up executing the same method. – Evk Apr 07 '17 at 14:34