Suppose I created a folder in "Documents" folder in my application sandbox and I called it "ID123".
From NSFileManager Class Reference I found out that I can create a new folder with one of these methods:
– createDirectoryAtURL:withIntermediateDirectories:attributes:error:
– createDirectoryAtPath:withIntermediateDirectories:attributes:error:
The question is how can I delete created directory?
You can use removeItemAtPath:error: OR removeItemAtURL:error: for doing this.
Like:
[[NSFileManager defaultManager] removeItemAtPath:yourPath error:nil];
or you can use:
[[NSFileManager defaultManager] removeItemAtURL:yourPathURL error:nil];
Depending on whether you're using the URL or path based approach, either use the...
- (BOOL)removeItemAtPath:(NSString *)path error:(NSError **)error
or
- (BOOL)removeItemAtURL:(NSURL *)URL error:(NSError **)error
...NSFileManager method.
For example:
NSError *removalError = nil;
if(![[NSFileManager defaultManager] removeItemAtPath:pathToFile error:&removalError]) {
// Something went wrong.
NSLog(#"%#", [removalError localizedDescription]);
}
In terms of recursive removal the supplied path (or URL depending on the method) can point at a directory containing items/sub-folders, etc. As per the Apple docs:
A path string indicating the file or directory to remove. If the path
specifies a directory, the contents of that directory are recursively
removed.
Incidentally, this is clearly defined within the "Creating and Deleting Items" section of the NSFileManager Class reference, so it would probably be worth the time to give that document a quick overview.
Related
I am working in a camera app where I can record video and save that in the directory like this:
file:///var/mobile/Applications/2683FFEC-63AB-4004-831B-DE38053CA472/Library/Caches/0C2E7E7C-5D78-4989-9C8E-259B3595BAC8-6498-0000042F24AB2D98.mov
when I go to the camera application I can see the video, but I want to delete this video when I quit the app, I did this so far
NSFileManager *fileManager = [[NSFileManager defaultManager];
[fileManager removeItemAtPath:THEABOVEURL error:&error];
but nothing happens and says cocoa error 4.The operation couldn’t be completed. No such file or directory
But I am sure that the file exists as I can play the video using the exact url mentioned above, what should I do now?
Cocoa Error 4 means
NSFileNoSuchFileError = 4, // Attempt to do a file system operation on a non-existent file
so it looks like that file just doesn't exist.
You may want to be sure that the file exists when you're going to delete it, maybe there is something wrong in the url that you are using?
- (BOOL)removeItemAtPath:(NSString *)path error:(NSError **)error
it takes a string as first parameter, I see on your code
[vedioPaths objectAtIndex:THEABOVEURL]
it looks like THEABOVEURL should be an index, and vedioPaths contains all the NSString representing the path of the files, Add some NSLog to see if these variables contain the right information to delete the file.
Ok, I solved it my way, I was trying to delete an url where the
- (BOOL)removeItemAtPath:(NSString *)path error:(NSError **)error
method wants NSUrl as parameter I converted this string as url and used this method
NSURL *urlfromString= [NSURL URLWithString:ABOVEURL];
[fileManager removeItemAtURL:urlfromString error:&error];
This solved my problem
I'm probably missing something really obvious here, but:
NSError *error;
NSURL *cachesDirectory = [[NSFileManager defaultManager] URLsForDirectory:NSCachesDirectory inDomains:NSUserDomainMask][0];
NSLog(#"Caches directory: %#", cachesDirectory);
NSURL *tmpDirectory = [[NSFileManager defaultManager] URLForDirectory:NSItemReplacementDirectory inDomain:NSUserDomainMask appropriateForURL:cachesDirectory create:YES error:&error];
NSLog(#"TMP directory: %#", tmpDirectory);
// Result:
// 2013-10-28 13:37:47.972 MyApp[220:907] Caches directory: file://localhost/var/mobile/Applications/029A4948-A67A-48E5-A35F-1BBCC744E9B0/Library/Caches/
// 2013-10-28 13:37:47.976 MyApp[220:907] TMP directory: file://localhost/var/mobile/Applications/029A4948-A67A-48E5-A35F-1BBCC744E9B0/Library/(A%20Document%20Being%20Saved%20By%20MyApp%2011)/
I was expecting my temporary directory to be created inside the caches directory. From the docs:
You can also use this method to create a new temporary directory for storing things like autosave files; to do so, specify NSItemReplacementDirectory for the directory parameter, NSUserDomainMask for the domain parameter, and a valid parent directory for the url parameter. After locating (or creating) the desired directory, this method returns the URL for that directory.
Also, the definition of url:
The name of a directory inside of which you want to create a unique temporary directory for autosaving documents or some other use. This parameter is ignored unless the directory parameter contains the value NSItemReplacementDirectory and the domain parameter contains the value NSUserDomainMask. When creating a temporary directory, the shouldCreate parameter is ignored and the directory is always created.
You can see that my temporary directory is being created inside Library. What am I doing wrong?
Looks like you are not doing anything wrong. I just tested it and found it behaving the way you described. Either the behavior does not comply with the doc or the docs are incorrect. I also happen to find the following link where people were discussing the exact same issue:
http://lists.apple.com/archives/cocoa-dev/2012/Feb/msg00197.html
I had read that I can mark folders with "do not backup" attribute.
As I understand, in such case all contents of directory will be excluded from backups.
In our app we need to exclude from backup all files in Documents directory (the files can be added or deleted from Documents during app execution).
We need to store our files in Documents because we use "Application supports iTunes file sharing" feature.
Can we mark Documents directory with "do not backup attribute"?
Does Apple permits this?
Could this become the reason to reject our app?
According to apple
In iOS 5.0 and earlier, put files in the
/Library/Caches directory to prevent them from being
backed up
In iOS 5.0.1 and later, put files in the
/Library/Application Support directory and apply the
com.apple.MobileBackup extended attribute to them. This attribute prevents the files from being backed up to iTunes or iCloud. If you
have a large number of support files, you may store them in a custom
subdirectory and apply the extended attribute to just the directory.
As far as I know
You can not mark documents directory with do not back up attribute
1)you may mark up the individual files inside the documents directory using below code snippet
- (BOOL)addSkipBackupAttributeToItemAtPath:(NSString *)filePathString {
NSURL *fileURL =
[NSURL fileURLWithPath:filePathString];
assert([[NSFileManager defaultManager]
fileExistsAtPath: [fileURL path]]);
NSError *error = nil;
BOOL success = [fileURL setResourceValue:[NSNumber numberWithBool:YES]
forKey:NSURLIsExcludedFromBackupKey
error:&error];
return success;
}
2)You may create a subdirectory inside documents folder and apply extended attribute to that.
you may set extended attribute using the below syntax.
int result = setxattr(path, attrName, myDataBytes, [myData length], 0, 0);
you can find more information on reading and writing extended attributes in the following link
I hope this helps
At a point in my code fileExistsAtPath: is returning NO for files that I have confirmed exist. I've been scratching my head at this and can't figure out why its not working, so changed it to this code as this directory absolutely exists but if it doesn't gets created anyway.
NSError* err = nil;
NSURL *dir = [[NSFileManager defaultManager] URLForDirectory:NSApplicationSupportDirectory
inDomain:NSUserDomainMask
appropriateForURL:nil
create: YES
error:&err];
BOOL exists = [[NSFileManager defaultManager] fileExistsAtPath:[dir absoluteString]];
After running this code the application directory folder exists and err is 0, yet exists is NO.
How can this be?
TIA
You should use [dir path], not [dir absoluteString].
I was bashing my head against the wall for a few hours. Apparently on each and every run in xcode (on simulator) the app directory path was changing. The UUID part of it.
So instead of storing the fullpath I ended up persisting the path postfix
and prefixing that with whatever storage class is implied: temporary, cached
or documents :-[ You realize why you have to sometimes run on device
even if you don't explore the depths of Metal, GLES or multitouch? ;^)
There is a distinction between path and url. A path in unix representation is the location where your particular file or directory exists. Like "/Users/username/Desktop/myfile.txt"
Wheres a url not only contains the location but scheme as well, e.g: http:// or https:// and in our case a file url (file:///Users/username/Desktop/myfile.txt)
Methods like fileExistsAtPath or removeItemAtPath need path in the parameter rather than a url.
While methods like copyItemAtURL:toURL:error:(NSError * _Nullable *)error expects a url.
Use path attribute of NSURL object to retrieve the path. absoluteString gives you the path along with the scheme.
My app is using a core data SQLite database. I would like to enable my users to use iCloud to sync it between devices - and I was thinking I could use UIManagedDocument.
I subclassed it, following Apple's documentation, and it is works when a new persistent store file needs to be created. However, when I try to use it to open my old persistent store file, I get the following exception thrown error:
"UIManagedDocument can only read documents that are file packages"
Does this mean that I need to migrate the old persistent store to a new store managed by UIManagedDocument? If so, do I need to do this manually (i.e. read each record one-at-a-time from the old store and write it into the new one)?
Thanks in advance!
UIManagedDocument creates packages(folders) rather than atomic stores. The store is still there but its buried in the package. If you right click on the file that is created in your Documents folder in the simulator you'll be able to see the structure. The default is
mydocument.foo
-> StoreContent
-> persistentStore
What you need to do is create a new extension for your app file type so for example if your database extension is .myappdb you need to create a new document type in your project settings which might be .myappdbw. You can copy all settings from the entry for .myappdb
Next at the point where you handle opening your legacy document at mydocumenturl instead of passing that to your persistent store co-ordinator you create the directory structure above.
NSURL *newurl = [[mydocumenturl URLByDeletingPathExtension] URLByAppendingPathExtension:#"myappdbw"];
NSURL *desturl = [newurl URLByAppendingPathComponent:#"StoreContent"];
[[NSFileManager defaultManager] createDirectoryAtURL:desturl withIntermediateDirectories:YES attributes:nil error:NULL];
NSURL *finalurl = [desturl URLByAppendingPathComponent:#"persistentStore"];
and then move the legacy database into the folder system you have created
[[NSFileManager defaultManager] moveItemAtURL:mydocumenturl toURL:finalurl error:NULL];
and then you can pass the bundle url to UIManagedDocument
UIManagedDocument *doc = [[UIManagedDocument alloc] initWithFileURL:newurl];
A link which will be useful for the iCloud integration is
http://developer.apple.com/library/ios/#releasenotes/DataManagement/RN-iCloudCoreData/_index.html
Its all a bit mysterious as the most of the promised sample code has failed to appear so far but on the other hand its mostly fairly simple to deduce. Have a look at WWDC2011 sessions 107,116 and 315 for more hints.
But note that if you are going to use this method for migrating your legacy docs DONT set the NSPersistentStoreUbiquitousContentNameKey at point you migrate because the package changes when you do. The doc above describes it quite well.
Thanks for this tip. I think I found an even simpler solution.
I just create a new UIManagedDocument with a different filename than my old persistent store location.
In my subclassed UIManagedDocument, I override the configurePersistentStoreCoordinatorForURL method and do the migration once there:
- (BOOL)configurePersistentStoreCoordinatorForURL:(NSURL *)storeURL ofType:(NSString *)fileType modelConfiguration:(NSString *)configuration storeOptions:(NSDictionary *)storeOptions error:(NSError **)error
{
// If legacy store exists, copy it to the new location
NSFileManager* fileManager = [NSFileManager defaultManager];
if ([fileManager fileExistsAtPath:legacyPersistentStoreURL.path])
{
NSError* thisError = nil;
[fileManager copyItemAtURL:legacyPersistentStoreURL toURL:storeURL error:&thisError];
[fileManager removeItemAtURL:legacyPersistentStoreURL error:&thisError];
}
return [super configurePersistentStoreCoordinatorForURL:storeURL ofType:fileType modelConfiguration:configuration storeOptions:storeOptions error:error];
}