NSFileManager removeItemAtPath does not remove file - ios

So, I searched the net and stackoverflow, checked the threads mentioned above this text box as possible already asked questions but the answers or tips couldn't help me because the code at first was OK and there was nothing wrong with it, it shouldn't be, because it is just not that hard. But for some reason I can not delete a earlier created file. The code:
NSArray *dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, true);
NSString *dbFile = [[NSString alloc] initWithString:[dirPaths[0] stringByAppendingPathComponent:#"database.db"]];
NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *error;
BOOL fileExists = [fileManager fileExistsAtPath:dbFile];
NSLog(#"Path to file: %#", dbFile);
NSLog(#"File exists: %d", fileExists);
NSLog(#"Is deletable file at path: %d", [fileManager isDeletableFileAtPath:dbFile]);
if (fileExists) {
BOOL success = [fileManager removeItemAtPath:dbFile error:&error];
if (!success) { NSLog(#"Error: %#", [error localizedDescription]); }
else { NSLog(#"probably deleted the file!"); }
}
The output:
2014-09-15 17:29:25.058 test[13862:60b] Path to file: /var/mobile/Applications/BB708129-C504-4E84-9C08-DF4ACE1369DC/Documents/database.db
2014-09-15 17:29:25.060 test[13862:60b] File exists: 1
2014-09-15 17:29:25.061 test[13862:60b] Is deletable file at path: 1
2014-09-15 17:29:25.063 test[13862:60b] probably deleted the file!
But every time I run the code It says the file exists and does not get deleted. Am I missing something?

Related

copyItemAtPath return NO but the error is nil during unit testing

I have a following code, which copies folder from the app bundle to the Documents folder.
- (void)moveTessdataToDocumentsDirectoryIfNecessary
{
// Useful paths
NSFileManager *fileManager = [NSFileManager defaultManager];
// Create specified folder in the Documents directory first
if ([fileManager fileExistsAtPath:self.dataPath] == NO) {
[fileManager createDirectoryAtPath:self.dataPath withIntermediateDirectories:YES attributes:nil error:nil];
}
NSString *tessdataFolderName = #"tessdata";
NSString *tessdataPath = [[NSBundle bundleForClass:self.class].resourcePath stringByAppendingPathComponent:tessdataFolderName];
NSString *destinationPath = [self.dataPath stringByAppendingPathComponent:tessdataFolderName];
if([fileManager fileExistsAtPath:destinationPath] == NO && [fileManager fileExistsAtPath:tessdataPath]) {
NSError *error = nil;
NSLog(#"found %#", tessdataPath);
NSLog(#"coping in %#", destinationPath);
BOOL res = [fileManager copyItemAtPath:tessdataPath toPath:destinationPath error:&error];
if (!res) {
NSLog(#"The result of copyItemAtPath == NO");
}
if(error != nil) {
NSLog(#"ERROR! %#", error.description);
}
}
}
It works fine in a sumilator and in a device.
The issue happens when I start unit tests for this function.
The output while unit testing is:
found /Users/kmakankov/Library/Developer/CoreSimulator/Devices/D28F7234-8C28-4325-BE7D-4DF113DF427E/data/Containers/Bundle/Application/EBD5C654-897B-4066-885B-986553D3459F/TestsProject.app/tessdata
coping in /Users/kmakankov/Library/Developer/CoreSimulator/Devices/D28F7234-8C28-4325-BE7D-4DF113DF427E/data/Containers/Data/Application/50D673A6-3F3E-42A1-98A1-DEAF9A4B2FBE/Documents/tes/tessdata
The result of copyItemAtPath == NO
So as you can see the copyItemAtPath return NO, but there is no error message, so I cannot understand what is the reason of the issue.
Furthemore, If I change copyItemAtPath with moveItemAtPath the function correctly moves the folder from the source to the destination during unit testing, so both source and destination paths are correct.
Does anybody knows what's wrong with copyItemAtPath?
Some extra info. I use iOS SDK 8.1.

ios: Where to put the Sqlite file in solution?

I am new to iOS development, I am making changes in an application which is using Sqlite. I am to add some new fields in some tables, I browsed DB with software and added new fields in
inventory_db_src.sqlite but when I see in emulator it uses inventory_db.sqlite which is strange as there is no inventory_db.sqlite file in solution and neither code creating DB through SQL script. And If I debug code it gets inventory_db.sqlite path successfully and never executes inventory_db_src.sqlite line and put inventory_db.sqlite in emulator where my new fields are not present as I put these in inventory_db_src.sqlite. pLease help me
BOOL success;
NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *error;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *dbPath = [documentsDirectory stringByAppendingPathComponent:#"inventory_db.sqlite"];
// [fileManager removeItemAtPath:dbPath error:nil];
success = [fileManager fileExistsAtPath:dbPath];
success = NO;
if (success) {
int savedVersion = [[NSUserDefaults standardUserDefaults] integerForKey:kVERSION_KEY];
if (kCURRENT_DB_VERSION != savedVersion) {
[fileManager removeItemAtPath:dbPath error:nil];
success = NO;
}
}
if (!success) {
// The writable database does not exist, so copy the default to the appropriate location.
NSString *defaultDBPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"inventory_db_src.sqlite"];
success = [fileManager copyItemAtPath:defaultDBPath toPath:dbPath error:&error];
if (!success) {
NSAssert1(0, #"Failed to create writable database file with message '%#'.", [error localizedDescription]);
}
}
_INVENTORY_DB = [[FMDatabase alloc] initWithPath:dbPath];
Line 6 in your code above is showing the name as inventory_db.sqlite, so that is the file your app will be using. You need to modify that to use the new database name. Be aware, that by modifying your database, you might have unexpected results so you will need to manage what DB version your app is using and make data corrections as needed. This is one nice feature that Core Data can assist in.
According to your statement it seems that old DB is cached in to your Emulator. please reset you Emulator by
iOS Simulator -> Reset content and settings
And it should work ...

NSFileManager createFileAtPath works in simulator but fails on device

I am trying to write some image data to disk on iOS, but while it's working perfectly in the Simulator, when I try it on a real iPad it fails (returns 0).
BOOL success = [[NSFileManager defaultManager] createFileAtPath:filePath contents:imageData attributes:nil];
The path in question looks something like this: /Library/Caches/_0_0_0_0_1100_1149.jpg and I've also tried /Documents/....
Is there any way to actually get an error code or something beyond just success/fail?
The simulator does not simulate the sandboxing of the file system that is enforced on a device. You can write anywhere on the sim, but on a device writing anywhere but one of your designated directories will fail.
I'm guessing that your path is badly formed somehow. Try logging your path and the path you get from NSCachesDirectory (as shown in your second post.) They are almost certainly different.
Turns out you have to programmatically obtain the directory. The iOS file system is not sandboxed like I expected.
NSString* pathRoot = NSSearchPathForDirectoriesInDomains( NSCachesDirectory, NSUserDomainMask, YES )[0];
If you're writing image data, why not try writing via NSData's [writeToFile: options: error:] method, the "error" parameter for which can give you some really useful hints as to why your file isn't writing.
This is illogical:
if ( !( [ fileManager copyItemAtPath:resourceDBFolderPath toPath:documentDBFolderPath error:&error ]))
You are checking if the method exists, not if it succeeded!!
I have some relevant code I've used in my project, I hope it may be help you some way or another:
-(void)testMethod {
NSString *resourceDBFolderPath;
NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *error;
NSArray *paths = NSSearchPathForDirectoriesInDomains( NSDocumentDirectory,
NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *documentDBFolderPath = [documentsDirectory stringByAppendingPathComponent:#"plans.gallery"];
BOOL success = [fileManager fileExistsAtPath:documentDBFolderPath];
if (success){
NSLog(#"Success!");
return;
}
else {
//simplified method with more common and helpful method
resourceDBFolderPath = [[NSBundle mainBundle] pathForResource:#"plans" ofType:#"gallery"];
//fixed a deprecated method
[fileManager createDirectoryAtPath:documentDBFolderPath withIntermediateDirectories:NO attributes:nil error:nil];
[fileManager copyItemAtPath:resourceDBFolderPath toPath:documentDBFolderPath
error:&error];
//check if destinationFolder exists
if ([ fileManager fileExistsAtPath:documentDBFolderPath])
{
//FIXED, another method that doesn't return a boolean. check for error instead
if (error)
{
//NSLog first error from copyitemAtPath
NSLog(#"Could not remove old files. Error:%#", [error localizedDescription]);
//remove file path and NSLog error if it exists.
[fileManager removeItemAtPath:documentDBFolderPath error:&error];
NSLog(#"Could not remove old files. Error:%#", [error localizedDescription]);
return;
}
}
}
}

copy OSX folder to iOS directory

I'm trying to copy a folder and it's contents to a sub-directory in the documentation directory and it's failing with the error:
"The operation couldn’t be completed. No such file or directory"
First I try to create a folder in the documentation directory like this:
NSString *diagramsDirectory = [docDirectory stringByAppendingPathComponent:#"Diagrams"];
if (![fileManager fileExistsAtPath:docDirectory isDirectory:&isDirectory] || !isDirectory)
{
NSError *error = nil;
NSDictionary *attr = [NSDictionary dictionaryWithObject:NSFileProtectionComplete
forKey:NSFileProtectionKey];
[fileManager createDirectoryAtPath:diagramsDirectory
withIntermediateDirectories:NO
attributes:attr
error:&error];
if (error) {
NSLog(#"error creating dir. path: %#", [error localizedDescription]);
}
}
NSLog(#"diagrams directory = %#", diagramsDirectory);
The console log seems to indicate this works:
diagrams directory = /Users/../iPhone Simulator/../Library/Documentation/Diagrams
However, when I then try to copy a folder called "Diagrams" from a directory on the Mac:
NSString *pathToDirectories = #"/User/Desktop/Project Resource Files/Files/";
NSError *error = nil;
NSArray *folders = [fileManager contentsOfDirectoryAtPath:pathToDirectories error:&error];
for (NSString *folder in folders) {
if ([folder isEqualToString:#"Diagrams"]) {
[self copyFolderAtPath:folder toDestinationFolderAtPath:docDirectory];
}
which calls the "copyFolderAtPath" method:
- (BOOL)copyFolderAtPath:(NSString *)sourceFolder toDestinationFolderAtPath:(NSString *)destinationFolder
{
destinationFolder = [destinationFolder stringByAppendingPathComponent:[sourceFolder lastPathComponent]];
NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *error = nil;
// check for destination folder
if ([fileManager fileExistsAtPath:destinationFolder])
{
if (![fileManager removeItemAtPath:destinationFolder error:&error])
{
NSLog(#"Could not remove old files. Error: %#", error);
return NO;
}
}
error = nil;
// copy destination
if (!([fileManager copyItemAtPath:sourceFolder toPath:destinationFolder error:&error])) {
NSLog(#"failed copying file at path %# to path %#. Error %#", sourceFolder, destinationFolder, error);
return NO;
}
return YES;
}
it returns "no" and I get the error.
Anyone got an idea what I'm doing wrong?
The device (and therefore the simulator) is isolated from the operating system so you cannot directly do file system copies. Imagine even if it let you do it from the simulator, how would a disconnected device running your app access the OS filesystem?
You will have to look into other options like having an application on the mac that opens sockets or having an http end point on the mac that the device copies from. Other options include syncing documents via iCloud or another cloud service. You can also transfer files via iTunes. I'm sure there's many other options ... Also checkout this

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?
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.
Now, start your app, without the file existing.
Dump file system data.
Create the file.
Dump file system data.
Dump file data.
You should see the file taking up about 200-250 bytes, and the file system free size should drop 8192.
Delete the file.
Dump file system data. Is probably at least as big as it was before deleting file.
Quit app (not in XCode -- double-click power, X the app).
Run the app.
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...
Your code to delete the file looks correct, but you are switching between URLs and Paths when you don't need to. You should also be checking for an error when you try to delete the file so that you can see why it doesn't work. Try this:
NSFileManager *fileManager = [NSFileManager defaultManager];
NSArray *directoryURLs = [fileManager URLsForDirectory:NSCachesDirectory
inDomains:NSUserDomainMask];
NSURL *directoryURL = [directoryURLs objectAtIndex:0];
NSURL *fileURL = [directoryURL URLByAppendingPathComponent:FILE_NAME];
if (!fileURL)
{
NSLog(#"Could not create URL for file.");
return;
}
NSError *err = nil;
if (![fileURL checkResourceIsReachableAndReturnError:&err])
{
NSLog(#"File is not reachable.\n"
"Error: %# %d %#", [err domain], [err code], [[err userInfo] description]);
return;
}
err = nil;
[fileManager removeItemAtURL:fileURL error:&err];
if (err)
{
NSLog(#"Unable to delete existing file.\n"
"Error: %# %d %#", [err domain], [err code], [[err userInfo] description]);
return;
}
May it be, that the length of the ˚FILE_NAME` is greater or equal to 300 chars? This brought me to similar issues with NSFileManager some time ago...

Resources