I am attempting to delete or overwrite an image within a specific directory. I grab all my images in an array and place in a table view. When an image is clicked photo roll is opened and the user chooses an image. when the imagepicker controller is being released I call out my methods to try and delete the original image and save the new image to the specific filepath. I receive a odd error when deleting the image and not sure how I can give a better log to save the image but it is not saving either. I would appreciate an input!
- (void)imagePickerController:(UIImagePickerController *)picker
didFinishPickingMediaWithInfo:(NSDictionary *)info {
NSLog(#"image picker did finish");
widgetImg.image = [info objectForKey:#"UIImagePickerControllerOriginalImage"];
change.enabled = YES;
[self saveImage:widgetImg.image :ImgName];
NSString *path = [NSString
stringWithFormat:#"/Library/Themes/%#/iSetUp/UserPhotos/%#",selectedThemeName,ImgName];
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]);
}
[self dismissModalViewControllerAnimated:YES];
}
- (void)saveImage:(UIImage*)image:(NSString*)imageName {
//convert image into .png format.
NSData *imageData = UIImagePNGRepresentation(image);
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *IMGPath = [NSString
stringWithFormat:#"/Library/Themes/%#/iSetUp/UserPhotos/",selectedThemeName];
[fileManager createFileAtPath:IMGPath contents:imageData attributes:nil];
NSLog(#"image saved");
}
2012-03-29 16:05:05.907 iSetUp[1258:707] image picker did finish
2012-03-29 16:05:09.046 iSetUp[1258:707] image saved
2012-03-29 16:05:09.047 iSetUp[1258:707] Path to file:
/Library/Themes/Modernistic/iSetUp/UserPhotos/IMG_0183.JPG
2012-03-29 16:05:09.048 iSetUp[1258:707] File exists: 1
2012-03-29 16:05:09.049 iSetUp[1258:707] Is deletable file at path: 0
2012-03-29 16:05:09.053 iSetUp[1258:707] Error: The operation couldn’t be completed.
(Cocoa error 513.)
You cannot directly access folders like that through the iOS SDK. You must save and read files using the system functions that return the proper path:
NSString *rootPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0]
NSString *pathToMenuLoopFile = [rootPath stringByAppendingPathComponent:#"Menu Loop.mp3"];
If you are looking to load files that you include in your Xcode project, please take a look at this post: Loading data files in iPhone project
The file is not deletable, either due to an ownership or permissions issue. See the discussion of isDeletableFileAtPath in
https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSFileManager_Class/Reference/Reference.html
Related
I cannot get the NSFileManager method replaceItemAtURL:withItemAtURL:backupItemName:options:resultingItemURL:error: to work in iOS 6. Apps that call this method and worked fine on iOS 5 have major issues on iOS 6. The problem does not occur on devices running versions of iOS below 6.0. The problem does not occur if the app is launched in the iOS Simulator by Xcode. Otherwise the problem seems to be universal.
Here is the test code I am trying to execute:
NSError *error;
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *destinationPath = [documentsDirectory stringByAppendingPathComponent:#"test.txt"];
NSString *sourcePath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"test.txt"];
// Create initial file in documents directory
if (![fileManager fileExistsAtPath:destinationPath])
{
BOOL fileCopied = [fileManager copyItemAtPath:sourcePath
toPath:destinationPath
error:&error];
if (!fileCopied)
[[self statusLabel] setText:[NSString stringWithFormat:#"Creation Error:\n\n%#",
[error localizedDescription]]];
}
// Replace file in documents directory with copy of file from app bundle
if ([fileManager fileExistsAtPath:destinationPath])
{
NSURL *destinationURL = [NSURL fileURLWithPath:destinationPath];
BOOL fileReplaced = [fileManager replaceItemAtURL:destinationURL
withItemAtURL:[NSURL fileURLWithPath:sourcePath]
backupItemName:nil
options:0
resultingItemURL:&destinationURL
error:&error];
if (!fileReplaced)
[[self statusLabel] setText:[NSString stringWithFormat:#"Replacement Error:\n\n%#",
[error localizedDescription]]];
else
[[self statusLabel] setText:#"Successfully replaced file."];
}
It creates the file in the documents directory, if it doesn’t already exist. It then attempts to replace the file in the documents directory with a copy of a file from the app bundle. It then reports the status of the file creation/replacement. As I said before, it replaces fine if it’s being run on iOS 5 or lower or if it’s being run in the iOS Simulator with Xcode attached to the process. However, if it’s run on an iOS 6 device or the iOS Simulator without Xcode the replacement fails and an error is returned. The localized error description is The operation couldn’t be completed. (Cocoa error 512.).
The user info dictionary for the error is:
{
NSFileNewItemLocationKey = "file://localhost/var/mobile/Applications/487FBB9E-A2BD-4CF2-BB38-F36764623C2F/Test.app/test.txt";
NSFileOriginalItemLocationKey = "file://localhost/var/mobile/Applications/487FBB9E-A2BD-4CF2-BB38-F36764623C2F/Documents/test.txt";
NSURL = "file://localhost/var/mobile/Applications/487FBB9E-A2BD-4CF2-BB38-F36764623C2F/Documents/test.txt";
NSUnderlyingError = "Error Domain=NSCocoaErrorDomain Code=513 \"The operation couldn\U2019t be completed. (Cocoa error 513.)\" UserInfo=0x1d58d350 {NSFilePath=/var/mobile/Applications/487FBB9E-A2BD-4CF2-BB38-F36764623C2F/Test.app/test.txt, NSURLUnsetValueKeysKey=<CFArray 0x1d58d180 [0x39b9d100]>{type = immutable, count = 2, values = (\n\t0 : <CFString 0x39b945b4 [0x39b9d100]>{contents = \"NSURLFileSecurityKey\"}\n\t1 : <CFString 0x39b943d4 [0x39b9d100]>{contents = \"NSURLCreationDateKey\"}\n)}, NSUnderlyingError=0x1d58d010 \"The operation couldn\U2019t be completed. Operation not permitted\", NSURL=file://localhost/var/mobile/Applications/487FBB9E-A2BD-4CF2-BB38-F36764623C2F/Test.app/test.txt}";
}
I have an app on the App Store which depends on this method. The live app continues to work without flaw on iOS 5, but on iOS 6 it is has huge problems due to the method failure. Does anyone know why this method is failing?
The NSFileManager method replaceItemAtURL:withItemAtURL:backupItemName:options:resultingItemURL:error: is not a copy method; it is a move method. I.e., the file isn’t replaced with a copy of the replacement file, but with the replacement file itself. Since an app is not supposed to be able to modify its own bundle, the above code should never have worked in any version of iOS.
To retain atomicity, the solution is to first save a copy of the replacement file to the temporary directory, then replace the file with the copy in the temporary directory.
Here is the fixed test code:
NSError *error;
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *sourcePath = [[NSBundle mainBundle] pathForResource:#"test" ofType:#"txt"];
NSString *destinationPath = [documentsDirectory stringByAppendingPathComponent:#"test.txt"];
// Create initial file in documents directory
if (![fileManager fileExistsAtPath:destinationPath])
{
BOOL fileCopied = [fileManager copyItemAtPath:sourcePath
toPath:destinationPath
error:&error];
if (!fileCopied)
[[self statusLabel] setText:[NSString stringWithFormat:#"Creation Error:\n\n%#", [error localizedDescription]]];
}
// Replace file in documents directory with copy of file from app bundle
if ([fileManager fileExistsAtPath:destinationPath])
{
// Create temporary file
NSString *tempPath = [NSTemporaryDirectory() stringByAppendingPathComponent:#"test.txt"];
BOOL tempCopied = [fileManager copyItemAtPath:sourcePath
toPath:tempPath
error:&error];
if (!tempCopied)
[[self statusLabel] setText:[NSString stringWithFormat:#"Temp Creation Error:\n\n%#", [error localizedDescription]]];
// Replace file with temporary file
NSURL *destinationURL = [NSURL fileURLWithPath:destinationPath];
BOOL fileReplaced = [fileManager replaceItemAtURL:destinationURL
withItemAtURL:[NSURL fileURLWithPath:tempPath]
backupItemName:nil
options:0
resultingItemURL:&destinationURL
error:&error];
if (!fileReplaced)
[[self statusLabel] setText:[NSString stringWithFormat:#"Replacement Error:\n\n%#", [error localizedDescription]]];
else
[[self statusLabel] setText:#"Successfully replaced file."];
}
I have this code, which should be working perfectly, but I can't udnerstand why it isn't:
+(NSString *)writeImageToFile:(UIImage *)image {
NSData *fullImageData = UIImageJPEGRepresentation(image, 1.0f);
NSString *path = [NSHomeDirectory() stringByAppendingPathComponent:#"Documents/Images/"];
NSFileManager *fileManager = [NSFileManager defaultManager];
BOOL isDirectory = NO;
BOOL directoryExists = [fileManager fileExistsAtPath:path isDirectory:&isDirectory];
if (directoryExists) {
NSLog(#"isDirectory: %d", isDirectory);
} else {
NSError *error = nil;
BOOL success = [fileManager createDirectoryAtPath:path withIntermediateDirectories:NO attributes:nil error:&error];
if (!success) {
NSLog(#"Failed to create directory with error: %#", [error description]);
}
}
NSString *name = [NSString stringWithFormat:#"%#.jpg", [JEntry generateUuidString]];
NSString *filePath = [path stringByAppendingPathComponent:name];
NSError *error = nil;
BOOL success = [fullImageData writeToFile:filePath options:NSDataWritingAtomic error:&error];
if (!success) {
NSLog(#"Failed to write to file with error: %#", [error description]);
}
return filePath;
}
It passed the directoryExists without an error, but when it gets to writeToFile, it gives me this error:
Error Domain=NSCocoaErrorDomain Code=512 "The operation couldn’t be completed. (Cocoa error 512.)" UserInfo=0x5634ee0 {NSFilePath=/var/mobile/Applications/5E25F369-9E05-4345-A0A2-381EDB3321B8/Documents/Images/18DAE0BD-6CB4-4244-8ED1-9031393F6DAC.jpg, NSUnderlyingError=0x5625010 "The operation couldn’t be completed. Not a directory"}
Any ideas why this might be?
I was able to reproduce your error when writing a file first in the path #"Documents/Images/", then trying to write the image using your code.
I think there are two possible scenarios for this:
1) You created that file by mistake at a previous execution of your app. This will be solved if you reset the simulator using the menu: iOS Simulator > Reset Contents and Settings, and uninstalling the app from your device: Long press > click on the x symbol.
2) There is some code somewhere else in your app that creates this file. If this is the case, you should find this code and remove it.
From FoundationErrors.h:
NSFileWriteUnknownError = 512
Try using withIntermediateDirectories:YES.
In my case a period '.' in the directory name (e.g. ~/Documents/someDir.dir/somefile) was the cause of the problem. I removed the offending character and the error disappeared.
As part of my app start-up i copy bundle files to my documents directory.
This works fine for three out of four of my files but the fourth one create a Zero KB file.
running on iOS 5.0 sim. I have cleaned the build several times and checked the file name capitalization vis correct.
the file appears in the directory but is zero kb and should be 24K
any help appreciated.
-(BOOL) CheckDBs: (NSString *)dbname
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory , NSUserDomainMask, YES);
NSString *documentsDir = [paths objectAtIndex:0];
NSString *dbPath = [documentsDir stringByAppendingPathComponent:dbname];
NSFileManager *fileManager = [NSFileManager defaultManager];
BOOL success = [fileManager fileExistsAtPath: dbPath];
NSLog(#"AppDelegate CheckDatabase: %# = %i", dbPath, success);
if (success) {
//NSLog(#"return YES");
return YES;
}
else {
return NO;
}
} // Complete - checks if files exist in the User Documents directory
-(void) copyDBs: (NSString *) dbname
{
//Using NSFileManager we can perform many file system operations.
NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *error;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory , NSUserDomainMask, YES);
NSString *documentsDir = [paths objectAtIndex:0];
NSString *dbPath = [documentsDir stringByAppendingPathComponent:dbname];
NSString *defaultDBPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:dbname];
BOOL success = [fileManager copyItemAtPath:defaultDBPath toPath:dbPath error:&error];
if (success) {
// Version 4.0 code
//NSDictionary *attribs = [NSDictionary dictionaryWithObject:NSFileProtectionComplete forKey:NSFileProtectionKey];
//success = [fileManager setAttributes:attribs ofItemAtPath:dbPath error:&error];
NSLog(#"AppDelegate copyDatase: %# = %d", dbPath, success);
}
//NSLog(#"AppDelegate copyDatase: %# = %d", dbPath, success);
if (!success) {
NSLog(#"Failed to copy database: '%#'", [error localizedDescription]);
// NSAssert1(0, #"Failed to create writable database file with message '%#'.", [error localizedDescription]);
}
}
Have you also checked the original file size?
Try resetting your simulator. From the NSFileManager documentation:
If a file with the same name already exists at dstPath, this method
aborts the copy attempt and returns an appropriate error.
Make sure the destination is empty and try again. Also, check the error object.
If all that checks out there has got to be an error in spelling the file name. Check if the exact file exists in bundle, NSLog wherever you use a file name or path, etc. You should find the error. Also check the appropriate folder in the Finder.
Instead of using
[[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:dbname]
try
[[NSBundle mainBundle] pathForResource:shortName ofType:#"db"]
Ok I figured out what is causing the problem.
as i run the app the appdidfinishlaunching method is not complete before one of the view controllers is loading. That view controller attempts to access one of the files being copied over from the bundle.
I'm guessing that sqlite creates the file when you attempt to access the database, it creates it with with a zero bytes length.
So when my appdidfinish launching method checks for the existance of the file it exists due to the sql call.
This is usually only going to be a problem prior to the first run of the app as after that the database will exist.
problem now is how do i get the appdidfinish launching to complete prior to the rest being allow to start as the view controller in question is part of the mainwindow.xib
Creating a custom directory which has all the images. Designing it custom because, it will help me to get the images as an when I need at various places in the configuration.
NSFileManager *filemgr;
filemgr = [NSFileManager defaultManager];
[filemgr createDirectoryAtPath: #"/Users/home/lifemoveson/test" withIntermediateDirectories:YES attributes: nil error:NULL];
I have placed images under test folder and are of .png types.
Is there a way to retrieve the images like below.
/** UPDATED again **/
Currently this folder is under Application_Home/Resources/ImageTiles/ as per Photoscroller example.
How can we change it to /Users/home/lifemoveson/test/ImageTiles/ folder ?
- (UIImage *)tileForScale:(CGFloat)scale row:(int)row col:(int)col
{
// we use "imageWithContentsOfFile:" instead of "imageNamed:" here because we don't want UIImage to cache our tiles
NSString *tileName = [NSString stringWithFormat:#"%#_%d_%d_%d", imageName, (int)(scale * 1000), col, row];
// Currently this folder is under <Application_Home>/Resources/ImageTiles/ as per Photoscroller example.
// How can we change it to /Users/home/lifemoveson/test/ImageTiles/ folder ?
NSString *path = [[NSBundle mainBundle] pathForResource:tileName ofType:#"png"];
UIImage *image = [UIImage imageWithContentsOfFile:path];
return image;
}
Applications running on iOS are sandboxed; you can't simply create directories wherever you please. Your createDirectoryAtPath: call will fail. You should use one of the directories set aside for your application instead.
Once you obtain the path for one of those directories, getting the path for files within them is simply a case of using NSString's stringByAppendingPathComponent: method.
Makin a call to the functions such as
NSString* newDirPath = [self createDirectoryWithName:#"Test"];
if (newDirPath) {
[self saveFile:#"MasterDB.sqlite" atPath:newDirPath];
}
which are implemented as follows
-(NSString*)createDirectoryWithName:(NSString*)dirName{
NSArray* directoryArray = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask , YES);
NSString* directoryPath = [directoryArray objectAtIndex:0];
NSString* newPath = [directoryPath stringByAppendingString:[NSString stringWithFormat:#"/%#",dirName]];
NSFileManager *filemamager = [NSFileManager defaultManager];
BOOL flag = [filemamager createDirectoryAtPath:newPath withIntermediateDirectories:YES attributes: nil error:NULL];
return flag == YES ?newPath: nil;
}
-(BOOL)saveFile:(NSString*)fileName atPath:(NSString*)path{
BOOL success;
// Create a FileManager object, we will use this to check the status
// of the File and to copy it over if required
NSFileManager *fileManager = [NSFileManager defaultManager];
// Check if the File has already been created in the users filesystem
NSString *filePath = [path stringByAppendingPathComponent:fileName];
success = [fileManager fileExistsAtPath:filePath];
// If the File already exists then return without doing anything
if(success) return YES;
// If not then proceed to copy the File from the application to the users filesystem
// Get the path to the database in the application package
NSString *pathFromApp = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:fileName];
// Copy the database from the package to the users filesystem
NSError *error = nil;
BOOL flag = [fileManager copyItemAtPath:pathFromApp toPath:filePath error:&error];
return flag;
}
might help you solve your problem. Creating a directory is achieved using first function and the second will let you save files from your application bundle to any of the previously created directory. I hope you can modify it save files located at places other than Application bundle to suit to your need.
hallo,
i have found some iphone-camera-video-saving avfoundation code examples
over the net (and also im tryin to write my own code but not finished it yet)
such examples process and do save the video (through AVAssetWriter)
from the camera capture input to file located in documments directory
(which i assume is the only option?)
but now - i do not even can see files in such directory to check
if my video is there; i think i should move such video file to
'camera roll', how to do that??
tnx
Transfer to Camera Roll - here's a link that should help.
To see what's in your Documents directory, here's a code snippet:
-(void) dump {
NSString *docsDir = [NSHomeDirectory() stringByAppendingPathComponent: #"Documents"];
NSFileManager *localFileManager = [NSFileManager defaultManager];
NSDirectoryEnumerator *dirEnum =
[localFileManager enumeratorAtPath:docsDir];
NSError *error=nil;
NSLog(#" Documents Directory: %#", docsDir);
NSString *file;
while (file = [dirEnum nextObject]) {
NSString *fullPath = [NSString stringWithFormat:#"%#/%#", docsDir,file];
NSDictionary *attrs = [localFileManager attributesOfItemAtPath:fullPath error:&error];
if ( error ) {
NSLog(#" error - %#", error);
} else {
//NSLog(#" file : %#", file);
NSInteger fsiz = [attrs fileSize];
NSString *ftyp = [attrs fileType];
NSDate *fmod = [attrs fileModificationDate];
NSLog(#" %9d : %# : %# : %#", fsiz, file, ftyp, fmod );
}
}
NSLog(#" ====== End Documents Directory ========");
}