Sign up ×
Stack Overflow is a community of 4.7 million programmers, just like you, helping each other. Join them, it only takes a minute:

NSFileManager removeItemAtURL performs only recursive deletion. There is no special treatment for non-empty directories.

How can I remove only empty directories by testing the condition beforehand? There is contentsOfDirectoryAtPath to get a list of files, which may be empty, but that's overkill.

Alternately, is there a function to remove it only if empty, like good ol' rmdir? Ah, I could just call that…

share|improve this question

3 Answers 3

up vote 5 down vote accepted

You have to use that if you want to stay in Foundation land, there is no other way.

But if you do so you introduce a race condition: After you list the contents of your directory and before you remove it some other program could write a new file there which then gets deleted. So you have to either accept the fact that you are deleting folders including all their content or you have to look for a different API.

You could use the POSIX rmdir function to achieve your goal like this:

NSString *path = [url path];
int result = rmdir( [path fileSystemRepresentation] );
if (result == 0) // everything ok
else // lookup error code from errno

If the directory is not empty you get the error code ENOTEMPTY.

share|improve this answer
    
Heh, I just edited the question to mention rmdir within one second of your answer submission. That's probably the best way, even if I am on iPhone. +1 – Potatoswatter Jul 4 '12 at 6:27
    
Even tho I suggested something else, I +1 this as well. Just because you're on an iPhone doesn't mean there's anything wrong with using POSIX library calls - I prefer them to Foundation for most things myself. – Jason Coco Jul 4 '12 at 6:32
    
@JasonCoco POSIX is great, but this is my first time in Foundation so I'm sticking to it more than I would otherwise, just for education. But iPhone does mean there will be no filesystem race condition. – Potatoswatter Jul 4 '12 at 6:33
    
@Potatoswatter that's true unless you're mucking about in the ubiquity container space :) in which case the race condition can return! – Jason Coco Jul 4 '12 at 6:40

It's not overkill... if you want a method that is something like - isEmptyDirectoryAtURL:, just make it:

@interface NSFileManager (EmptyDirectoryAtURL)
- (BOOL)isEmptyDirectoryAtURL:(NSURL*)url;
@end

@implementation NSFileManager (EmptyDirectoryAtURL)

- (BOOL)isEmptyDirectoryAtURL:(NSURL*)url
{
  // This assumes you know the URL you have is actually a
  // directory and should be enhanced to ensure that
  return ([[self contentsOfDirectoryAtURL:url includingPropertiesForKeys:nil options:0 error:NULL] count] <= 1);
}

@end
share|improve this answer
    
Why is one item allowed? – Potatoswatter Jul 4 '12 at 6:32
    
@Potatoswatter If the URL didn't exist anyway, it's going to return 0, but if the URL is there and empty, the magic self-reference will be part of the returned contents (the . directory), so it will actually always be 1 if it's there and empty. You can pass an option to exclude hidden files, which includes the . but then you're directory's not actually empty, so better not to. – Jason Coco Jul 4 '12 at 6:33
    
Thanks! +1 (dot dot dot) – Potatoswatter Jul 4 '12 at 6:37
    
In practice, I have not seen the '.' directory returned in the array that comes back from contentsOfDirectory. Although there is a file that typically does come back that is delete-able, it is '.DS_Store' which is created by spotlight. The problem with using the <= 1 logic though is that spotlight takes a little time to create the file in normal directories, and never creates it inside packages. So the net effect is that you will end up getting false positives when there is one file/folder in the url, and there is no .DS_Store file. I would recommend that you check explicitly for .DS_Store – Scott Allen Aug 30 '13 at 16:09

Why not implement the NSFileManager delegate method "fileManager:shouldRemoveItemAtURL:" and in that delegate method implementation, do a quick check to see if A) the item is a directory and B) if the directory is empty before returning "YES".

share|improve this answer
    
That's not an answer at all, nor a good suggestion. I should replace a specific if statement in one place with a global delegate method, maybe off in a different file, that arbitrates deletion for everything? – Potatoswatter Jul 4 '12 at 6:30
    
Yes it is a fine answer and a fine suggestion. At "remoteItemAtURL" time, NSFileManager calls that delegate method before doing the removal to find out if it's okay to remove that something. In your case, you only want to remove things that pass a certain criteria. E.G. empty directories. For my own code, I'd rather rely on what the Cocoa framework provides, but it sounds like you're much more comfortable with straight C / UNIX / POSIX stuff. So +1 to Sven's superior answer. – Michael Dautermann Jul 4 '12 at 6:33
    
I asked how to check if a directory is empty. Your suggestion is to make a new function that takes a URL and checks if it's an empty directory. Not an answer. – Potatoswatter Jul 4 '12 at 6:35
    
Also, you can create your own NSFileManager via alloc/init for this specific situation. You don't need to hook the delegate up to the singleton. I was wondering if when you called removeItemAtURL: on a directory, fileManager:shouldRemoveItemAtURL: would be called for its contents first. If that is the case, you could abort if you discover it trying to delete a file instead of your directory. – borrrden Jul 4 '12 at 6:35
    
I'll leave my answer here, even though it's gonna collect down votes, because your question isn't clear (you asked how to remove only empty directories). – Michael Dautermann Jul 4 '12 at 6:37

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.