iPhone/Objective C: Can't delete a file - objective-c

In my application, I let the user record a sound clip and later, if the user chooses, I want him to be able to delete it.
This is the code I use:
NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *error;
NSLog(#"File exists: %d", [fileManager fileExistsAtPath:path]);
NSLog(#"Is deletable file at path: %d", [fileManager isDeletableFileAtPath:path]);
[fileManager removeItemAtPath:path error:&error];
if (error != nil)
{
NSLog(#"Error: %#", error);
NSLog(#"Path to file: %#", path);
}
The problem is that fileExistsAtPath and isDeletableFileAtPath return null and the removeItemAtPath doesn't work, and throws this error,
Error: Error Domain=NSCocoaErrorDomain Code=4 UserInfo=0x391b7f0 "Operation could not be completed. (Cocoa error 4.)"
The path has this form:
/Users/andrei/Library/Application%20Support/iPhone%20Simulator/User/Applications/5472B318-FA57-4F8D-AD91-7E06E9609215/Documents/1280913694.caf
There is a file there called 1280913694.caf, but it doesn't pick it up. Does it have something to do with the way in which the path should be represented?
The path works when playing the audio file with AVAudioPlayer.
I've also changed the %# to %d for fileExistsAtPath and isDeletableFileAtPath and the answer is 0, which I suppose means FALSE.
The name of the file is stored in a database, and the path to the file is retrieved with this method:
-(NSString *)returnFullPathToDirectory
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
return documentsDirectory;
}
After I get this value, I use it in the following code
NSString *filePath = [documentsDirectory stringByAppendingPathComponent:fileName];

Your check for (error != nil) is incorrect. You should set a BOOL to the return value of the method and use that to handle error conditions as it is possible for the method to complete successfully and for error to be non nil afterwards. So, the file might actually have been deleted but you are getting an incorrect error back.
You should also not try to delete the file if it doesn't exist.
Also, I usually just log the error's localizedDescription as that is easier to read
This code works in my project (path was defined elsewhere):
NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *error;
BOOL fileExists = [fileManager fileExistsAtPath:path];
NSLog(#"Path to file: %#", path);
NSLog(#"File exists: %d", fileExists);
NSLog(#"Is deletable file at path: %d", [fileManager isDeletableFileAtPath:path]);
if (fileExists)
{
BOOL success = [fileManager removeItemAtPath:path error:&error];
if (!success) NSLog(#"Error: %#", [error localizedDescription]);
}
related answer:
NSError: Does using nil to detect Error actually turn off error reporting?

The url encoded file path looks suspicious to me. I read somewhere that iPhone file paths should be represented as URL these days, but I don't think spaces need to be url encoded.
Try removing the %20's from your path and trying again?

try to change
NSFileManager *fileManager = [NSFileManager defaultManager];
to:
NSFileManager *fileManager = [NSFileManager new];

Related

How to copy database file in Application Support directory in Cocoa without losing data?

I have tried this code but it creates BLANK database.sqlite file in document directory.
- (void)createEditableCopyOfDatabaseIfNeeded
{
// First, test for existence.
BOOL success;
NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *error;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *writableDBPath = [documentsDirectory stringByAppendingPathComponent:#"prediction.sqlite"];
success = [fileManager fileExistsAtPath:writableDBPath];
if (success) return;
// The writable database does not exist, so copy the default to the appropriate location.
NSString *defaultDBPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"prediction.sqlite"];
success = [fileManager copyItemAtPath:defaultDBPath toPath:writableDBPath error:&error];
if (!success) {
NSAssert1(0, #"Failed to create writable database file with message '%#'.", [error localizedDescription]);
}
}
How do I ensure that when I copy database file it does not create an empty database?
Any help would be greatly appreciated.
First your code were not attempts to create a database file.
So... You just want to copy the database file “prediction.sqlite” from source bundle to UserDomain dir?
If this is your purpose,You should pay attention to the code:
if (success) return;
// The writable database does not exist, so copy the default to the appropriate location.
The correct should be:
if (!success) return;
// The writable database does not exist, so copy the default to the appropriate location.
The directories returned by NSSearchPathForDirectoriesInDomains are not guaranteed to exist; you need to create them yourself, if necessary (see the documentation). NSFileManager's createDirectoryAtPath:withIntermediateDirectories:attributes:error: can help with that.#Anomie
try those code:(before you copy the "prediction.sqlite" file, you need add the file in to your project bundle.):
- (void)createEditableCopyOfDatabaseIfNeeded
{
// First, test for existence.
BOOL success;
NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *error;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *writableDBPath = [documentsDirectory stringByAppendingPathComponent:#"prediction.sqlite"];
success = [fileManager fileExistsAtPath:writableDBPath];
if (!success){
// create the directories, because the directories returned by NSSearchPathForDirectoriesInDomains are not guaranteed to exist
if (![fileManager createFileAtPath:writableDBPath contents:nil attributes:nil]) {
return;
}
}
// The writable database does not exist, so copy the default to the appropriate location.
NSString *defaultDBPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"prediction.sqlite"];
// remove the same file, before you copy the file
[fileManager removeItemAtPath:writableDBPath error:nil];
success = [fileManager copyItemAtPath:defaultDBPath toPath:writableDBPath error:&error];
if (!success) {
NSAssert1(0, #"Failed to create writable database file with message '%#'.", [error localizedDescription]);
}
}

How to replace a file or folder by using NSFileManager?

For using "copyItemAtPath" method of NSFileManager, if exists the same file or folder, occur error.
Is there the replace feature in NSFileManager?
(If exists the same file, delete and copy If not, just copy.)
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self generateTableContents];
}
- (void)generateTableContents {
NSFileManager *fileManager = [NSFileManager defaultManager];
NSArray *appsDirectory = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentPath = [appsDirectory objectAtIndex:0];
[fileManager changeCurrentDirectoryPath:documentPath];
[fileManager createDirectoryAtPath:#"user_List1" withIntermediateDirectories:YES attributes:nil error:nil];
NSString *bundlePath = [[NSBundle mainBundle] resourcePath];
NSError *error; // to hold the error details if things go wrong
NSString *sourcePath = [[NSBundle mainBundle] pathForResource:#"IMG_0523" ofType:#"JPG"];
if ([fileManager copyItemAtPath:sourcePath toPath: #"./user_List1/newIMG_0523.JPG" error:&error]) {
NSLog(#"Copy complete!");
} else {
NSLog(#"Copy Failed : %#", error);
}
if ([fileManager copyItemAtPath:#"./user_List1" toPath: #"./user_List2" error:&error]) {
NSLog(#"Copy complete!");
} else {
NSLog(#"Copy Failed : %#", error);
}
}
Excuted result is complete.
/Users/nice7285/Library/Caches/appCode10/DerivedData/tempPrg-dd15264d/Build/Products/Debug-iphonesimulator/tempPrg.app/tempPrg
Simulator session started with process 1184
2012-10-04 06:28:32.653 tempPrg[1184:11303] Copy complete!
2012-10-04 06:28:32.672 tempPrg[1184:11303] Copy complete!
Process finished with exit code 143
But When already exist folder.
Result is fail.
2012-10-04 06:48:31.488 tempPrg[1243:11303] Copy Failed
2012-10-04 06:48:31.497 tempPrg[1243:11303] Copy Failed
You need to do an atomic save, for example:
NSData *myData = ...; //fetched from somewhere
[myData writeToFile:targetPath atomically:YES];
But since you're using copyItemAtPath, I have no idea if atomically works with it so I would just go for the quick dirty hack:
if ([fileManager fileExistsAtPath:txtPath] == YES) {
[fileManager removeItemAtPath:txtPath error:&error]
}
NSString *resourcePath = [[NSBundle mainBundle] pathForResource:#"txtFile" ofType:#"txt"];
[fileManager copyItemAtPath:resourcePath toPath:txtPath error:&error];
Sources: IOS: copy a file in documents folder
Starting with iOS 4 (and macOS 10.7) there is an explicit method for replacing one item with another. It even keeps the properties of the original file (optional)
- (BOOL)replaceItemAtURL:(NSURL *)originalItemURL withItemAtURL:(NSURL *)newItemURL backupItemName:(NSString *)backupItemName options:(NSFileManagerItemReplacementOptions)options resultingItemURL:(NSURL * _Nullable *)resultingURL error:(NSError * _Nullable *)error;
Replaces the contents of the item at the specified URL in a manner
that ensures no data loss occurs.
replaceItemAtURL:withItemAtURL:backupItemName:options:resultingItemURL:error:

Getting error while trying to make writeable copy of sqlite

I have a copy of my db in Supporting Files folder. I need update a couple of tables and I am trying to use method to make writeable copy of db.
- (void) createEditableDatabase
{
BOOL success;
NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *error;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES);
NSString *documentsDir = [paths objectAtIndex:0];
NSString *writableDB = [documentsDir stringByAppendingPathComponent:#"yc_ch.db"];
success = [fileManager fileExistsAtPath:writableDB];
NSString *defaultPath = [[[NSBundle mainBundle]resourcePath]stringByAppendingPathComponent:#"yc_ch.db"];
success = [fileManager copyItemAtPath:defaultPath toPath:writableDB error:&error];
if (!success)
{
NSAssert1(0, #"Failed to create writable database file:'%#'.", [error localizedDescription]);
}
}
I have created (typed, physically) the 'Documents' folder in the root. At moment hierarchy of docs looks like this:
When I run my app. I am getting NSAssert1(0, #"Failed to create writable database file:'%#'.", [error localizedDescription]);.
What's wrong with it?
You copy the file even if the file already exists in the Document, I think NSFileManager copyFileAtPath: will return NO if file already exists at destination, hence failing your check and raising your NSAssert
success = [fileManager fileExistsAtPath:writableDB];
if (success)
{
return;
}
So the file isn't copied over if it already exists in your document. If that's what causing the error, can you actually post the assertion, [error localizedDescription] will at least tell you what is wrong with it at the moment.
Edit:
- (void) createEditableDatabase
{
BOOL success;
NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *error;
NSString *writableDB = [[NSHomeDirectory() stringByAppendingPathComponent:#"Documents"] stringByAppendingPathComponent:#"yc_ch.db"];
NSLog(#"Document path = %#", writableDB);
success = [fileManager fileExistsAtPath:writableDB];
if (success)
{
return;
}
NSString *defaultPath = [[NSBundle mainBundle] pathForResource:#"yc_ch" ofType:#"db"];
NSLog(#"defaultPath = %#", defaultPath);
error = nil;
success = [fileManager copyItemAtPath:defaultPath toPath:writableDB error:&error];
if (!success)
{
NSAssert1(0, #"Failed to create writable database file:%#", [error localizedDescription]);
}
if (error)
{
NSLog(#"error = %#", [error localizedDescription]);
}
}

unable to play audio file from document?

when ever i try to play audio this error appears
2010-08-27 09:13:40.466 VoiceRecorder[3127:207] Failed with reason: The operation couldn’t be completed. (OSStatus error -43.)
what does it mean
I am physically storing file in Iphone Document folder and copying its name in my database
so when ever I play it from database its correctly get file path
and file name from document and database concat perfectly but unable to play
2010-08-30 12:22:00.592 VoiceRecorder[8140:207] /Users/Username/Library/Application Support/iPhone Simulator/4.0.1/Applications/4BF0B5C7-59C9-462F-94EC-
662EBCE8505E/Documents/30Aug10_12_21_58.aif
2010-08-30 12:22:00.593 VoiceRecorder[8140:207] 30Aug10_12_21_58.aif
2010-08-30 12:22:00.618 VoiceRecorder[8140:207] Failed with reason: The operation couldn’t be completed. (OSStatus error -43.)
need an urgent reply
here is my code
-(IBAction)playevent{
VoiceRecorderAppDelegate *appDelegate=(VoiceRecorderAppDelegate*)[[UIApplication sharedApplication]delegate];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDir = [paths objectAtIndex:0];
NSString *fullpath = [documentsDir stringByAppendingPathComponent:appDelegate.filenamefrompath];
NSFileManager *fileManager = [NSFileManager defaultManager];
// Check if the database has already been created in the users filesystem
BOOL success = [fileManager fileExistsAtPath:fullpath];
// If the database already exists then return without doing anything
if(success) { NSLog(#"Yes exists"); }else{ NSLog(#"no"); }
//return [documentsDir stringByAppendingPathComponent:appDelegate.filenamefrompath];
NSError* err;
NSLog(#"%#",fullpath);
player = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:fullpath] error:&err];
//NSString *filePath = [[NSBundle mainBundle] pathForResource:appDelegate.filenamefrompath ofType:#"aif"];
// NSURL *fileURL = [[NSURL alloc] initFileURLWithPath:filePath];
// player = [[AVAudioPlayer alloc] initWithContentsOfURL:fileURL error:nil];
NSLog(#"%#",appDelegate.filenamefrompath);
player.delegate = self;
if( err ){
//bail!
NSLog(#"Failed with reason: %#", [err localizedDescription]);
}
[player play];
}
Please check my code for error
The code looks OK on the surface
Strangely tracking down the errors definitions is not entirely easy
They are in MacErrors.h
fnfErr = -43, /*File not found*/
Can you verify that the URL you are feeding the player in [NSURL fileURLWithPath:fullpath] is valid.
And more to the point is the file you are trying to play there in the Sim folder?
and off topic if this is supposed to be an IBAction then the signature should be
-(IBAction)playevent:(id)sender

SQLite Step Failed: attempt to write a readonly database , using wrapper

I keep getting an error "SQLite Step Failed: attempt to write a readonly database" when using this code to copy a database:
-(void)createEditableCopyOfDatabaseIfNeeded
{
// Testing for existence
BOOL success;
NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *error;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *writableDBPath =
[documentsDirectory stringByAppendingPathComponent:#"Money.sqlite"];
success = [fileManager fileExistsAtPath:writableDBPath];
if (success)
return;
// The writable database does not exist, so copy the default to
// the appropriate location.
NSString *defaultDBPath = [[[NSBundle mainBundle] resourcePath]
stringByAppendingPathComponent:#"Money.sqlite"];
success = [fileManager copyItemAtPath:defaultDBPath
toPath:writableDBPath
error:&error];
if(!success)
{
NSAssert1(0,#"Failed to create writable database file with Message : '%#'.",
[error localizedDescription]);
}
}
I am using the above code in AppDelegate
and this:
NSString *writableDBPath =
[[NSBundle mainBundle] pathForResource:#"Money"
ofType:#"sqlite"];
In ViewController.m
I am using http://th30z.netsons.org/2008/11/objective-c-sqlite-wrapper/ what am I doing wrong?
This is happening again and again... It was working fine before but again the problem started.
The problem is that you cannot write anything to your bundle. To be able to change your database you need to copy it to application's documents or caches folder and work with that copy.