Search code examples
iosnsfilemanager

NSFileManager removeItemAtPath: error: did not actually free disk space


NSFileManager* fileManager = [NSFileManager defaultManager];
NSURL* url = [[fileManager URLsForDirectory:NSCachesDirectory inDomains:NSUserDomainMask] lastObject];
NSString* directory = [url path];
NSString* filePath = [directory stringByAppendingPathComponent:FILE_NAME];
if ([fileManager fileExistsAtPath:filePath])
{
    [fileManager removeItemAtPath:filePath error:nil];
}   

Here's my code. When it is executed, the file is deleted, but the space remains occupied. Here's the code for storing something into the file.

NSFileManager* fileManager = [NSFileManager defaultManager];
NSURL* url = [[fileManager URLsForDirectory:NSCachesDirectory inDomains:NSUserDomainMask] lastObject];
NSString* directory = [url path];
NSString* filePath = [directory stringByAppendingPathComponent:FILE_NAME];
NSArray* oldArray = nil;
if ([fileManager fileExistsAtPath:filePath])
{
    oldArray = [[NSArray alloc] initWithContentsOfFile:filePath];
    [fileManager removeItemAtPath:filePath error:nil];
}
NSMutableArray* mergeArray = [[NSMutableArray alloc] initWithArray:arrayOfPersons];
[mergeArray addObjectsFromArray:oldArray];
if ( [mergeArray writeToFile:filePath atomically:YES]) NSLog(@"Written");

By the way, it cost 1 MB to store an array with only 1 object(an NSDictionary with 2 keys). Is there a cheaper way to store it?


Solution

  • You need to be much more careful with your experiments. The unix file system does lots of stuff with files. In fact, when you "delete" a file, all you do is unlink it from the file system. If that file is open with another file descriptor, anywhere in the OS, it will remain open.

    Furthermore, there are lots of optimizations to reuse file nodes. Just because you delete a file, does not mean that space goes back automatically. It could be "reserved" in your app for several reasons, for other files to use. No sense giving it back to the file system until the file system needs it.

    settings->general->usage is a very rough measurement of file system utilization. A better measurement would be accessing the attributes of the file and file system directly.

    Using your code as a base, consider this:

    - (NSString*)workingDirectory {
        NSFileManager* fileManager = [NSFileManager defaultManager];
        NSURL* url = [[fileManager URLsForDirectory:NSCachesDirectory
                                          inDomains:NSUserDomainMask] lastObject];
        return [url path];
    }
    
    - (NSString*)filePath {
        return [[self workingDirectory] stringByAppendingPathComponent:FILE_NAME];
    }
    

    Now, you can see all the attributes of the entire file system with this:

    NSDictionary *attributes = [[NSFileManager defaultManager]
        attributesOfFileSystemForPath:[self workingDirectory] error:0];
    NSLog(@"file system attributes: %@", attributes);
    

    and those for the specific file with this:

    NSDictionary *attributes = [[NSFileManager defaultManager]
        attributesOfItemAtPath:[self filePath] error:0];
    NSLog(@"file attributes: %@", attributes);
    

    Pay attention to NSFileSystemFreeSize and NSFileSize.

    Run your app, and dump both of these values. Create your file, and dump them again. Delete the file, and dump them again.

    After all that, you may actually see the NSFileSystemFreeSize go UP, even after the delete. Remember, the system itself is creating temporary files, and is probably caching those file system nodes for future use.

    You can get more consistent results if you quit all other apps. Then, quit yours (double-click power button, X all running apps). Delete the file before doing this.

    1. Now, start your app, without the file existing.

    2. Dump file system data.

    3. Create the file.

    4. Dump file system data.

    5. Dump file data.

    You should see the file taking up about 200-250 bytes, and the file system free size should drop 8192.

    1. Delete the file.

    2. Dump file system data. Is probably at least as big as it was before deleting file.

    3. Quit app (not in XCode -- double-click power, X the app).

    4. Run the app.

    5. Dump file system data. You should see the data back to about what it was when you started earlier.


    In conclusion, while it may look like the file system has not released the data, it really has, but maybe the tool you are using to query just does not know the details of the file system.

    Note, also, that when an app is running, it will use lots of file system resources for stuff that you are not explicitly doing.

    I hope that made sense...