NSFileManager not saving Data - ios

I am trying to save data into a directory created by NSFileManager but when I try and retrieve the data and NSLog it I get null. Also, when you create a directory does that mean you create a folder at a specified url path? Heres the code I am using
NSError *error = nil;
NSFileManager *manager = [[NSFileManager alloc] init];
NSArray *urlsArray = [manager URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask];
NSLog(#"%#", urlsArray);
// This will create a new url and append a photo title to the end
NSURL *url = [[urlsArray lastObject] URLByAppendingPathComponent:[NSString stringWithFormat:#"%#", [self.recentPhoto objectForKey:FLICKR_PHOTO_TITLE]]];
NSLog(#"%#", url);
NSString *urlString = [NSString stringWithFormat:#"%#", [url absoluteString]];
NSLog(#"%#", urlString);
//create the directory
if(![manager fileExistsAtPath:urlString isDirectory:YES]){
BOOL success = [manager createDirectoryAtURL:url withIntermediateDirectories:YES attributes:nil error:&error];
if (!success) {
NSLog(#"Error creating data path: %#", [error localizedDescription]);
}
}
//get url for a photo image and then store it.
NSURL *imageURL = [FlickrFetcher urlForPhoto:self.recentPhoto format:FlickrPhotoFormatLarge];
NSData *imageData = [[NSData alloc] initWithContentsOfURL:imageURL];
[imageData writeToURL:url atomically:YES];
//get data to check if its stored
NSData *checkImageData = [[NSData alloc] initWithContentsOfURL:url];
//This returns null
NSLog(#"%#", checkImageData);
//this returns 0
NSLog(#"%d", [manager isReadableFileAtPath:urlString]);

There are several issues with your code.
This:
NSURL *url = [[urlsArray lastObject] URLByAppendingPathComponent:[NSString stringWithFormat:#"%#", [self.recentPhoto objectForKey:FLICKR_PHOTO_TITLE]]];
should be:
NSURL *url = [[urlsArray lastObject] URLByAppendingPathComponent:[self.recentPhoto objectForKey:FLICKR_PHOTO_TITLE]];
This:
NSString *urlString = [NSString stringWithFormat:#"%#", [url absoluteString]];
should be:
NSString *urlString = [url path];
This:
BOOL success = [manager createDirectoryAtURL:url withIntermediateDirectories:YES attributes:nil error:&error];
should be:
BOOL success = [manager createDirectoryAtURL:[url URLByDeletingLastPathComponent] withIntermediateDirectories:YES attributes:nil error:&error];
This:
[imageData writeToURL:url atomically:YES];
should be:
NSError *error = nil;
BOOL res = [imageData writeToURL:url options:NSDataWritingAtomic error:&error];
if (!res) {
NSLog(#"Unable to write to %#: %#", url, error);
}
The primary issue was the use of absoluteString instead of path to convert the URL to a file path. Secondary was passing the filename instead of the path when creating the directory. The needless use of stringWithFormat: didn't cause any issues but please break that habit now. Only use stringWithFormat: when you actually need to format a string. It is NOT needed to assign a string to a string variable.

You didn't specify a file name for your image inside the directory, this can be solved by adding this line right after the directory is created :
// Right after the directory is created (I suppose the format is png) :
url = [url URLByAppendingPathComponent:#"image.png"];
// Now you can continue with the rest of your code :
//get url for a photo image and then store it.
NSURL *imageURL = [FlickrFetcher urlForPhoto:self.recentPhoto format:FlickrPhotoFormatLarge];
NSData *imageData = [[NSData alloc] initWithContentsOfURL:imageURL];
[imageData writeToURL:url atomically:YES];
//get data to check if its stored
NSData *checkImageData = [[NSData alloc] initWithContentsOfURL:url];
//This returns null
NSLog(#"%#", checkImageData);
//this returns 0
NSLog(#"%d", [manager isReadableFileAtPath:urlString]);

I have never created an instance of a file manager. I have always simply used the default.
See if this helps:
NSFileManager *manager = [NSFileManager defaultManager];

Related

How to copy NSData contents to temporary file?

I'm downloading what can be a large file from an S3 bucket and want to save it between view controllers to be consumed a short time later. I like the tmp directory because of less limitations on file size and there also does not seem to be a reason for me to save this in the Documents directory.
I can construct a path to tmp with:
NSURL *tmpDirURL = [NSURL fileURLWithPath:NSTemporaryDirectory() isDirectory:YES];
NSURL *fileURL = [[tmpDirURL URLByAppendingPathComponent:#"image"] URLByAppendingPathExtension:#"png"];
NSLog(#"fileURL: %#", [fileURL path]);
but am unsure how to write/overwrite the downloaded NSData * to that path.
I basically just want to what I can more clearly express with the command line:
wget https://example.com/image.png
cp image.png /tmp/
Looks like the class reference may expose a method to do just this:
https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSData_Class/
EDIT
My solution that works. Ended up being that I needed to use writeToURL. Inspiration taken from here:
http://nshipster.com/nstemporarydirectory/
https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSURL_Class/#//apple_ref/occ/clm/NSURL/fileURLWithPath:isDirectory:
#define S3_LATEST_IMAGE_FILEPATH #"test-image.png"
// Write the downloaded result to the filesystem
NSError *error;
NSString *fileName = [NSString stringWithFormat:#"%#_%#", [[NSProcessInfo processInfo] globallyUniqueString], S3_LATEST_IMAGE_FILEPATH];
NSURL *directoryURL = [NSURL fileURLWithPath:[NSTemporaryDirectory() stringByAppendingPathComponent:[[NSProcessInfo processInfo] globallyUniqueString]] isDirectory:YES];
[[NSFileManager defaultManager] createDirectoryAtURL:directoryURL withIntermediateDirectories:YES attributes:nil error:&error];
if (error) {
NSLog(#"Error1: %#", error);
return;
}
NSURL *fileURL = [directoryURL URLByAppendingPathComponent:fileName];
NSString *path = fileURL.absoluteString;
NSLog(#"fileURL.absoluteString: %#", path);
[data writeToURL:fileURL options:NSDataWritingAtomic error:&error];
if (error) {
NSLog(#"Error: %#", error);
}
You can directly write the NSData into the path by
NSURL *tmpDirURL = [NSURL fileURLWithPath:NSTemporaryDirectory() isDirectory:YES];
NSURL *fileURL = [[tmpDirURL URLByAppendingPathComponent:#"newest-fw"] URLByAppendingPathExtension:#"zip"];
NSString *path= fileURL.absoluteString;
//data would be the NSData that you get from the S3 bucket
NSError *error;
[[NSFileManager defaultManager] createDirectoryAtURL: fileURL withIntermediateDirectories:NO attributes:nil error:&error];
[data writeToFile:path options:NSDataWritingAtomic error:&error];
NSData's writeToFile method will automatically overwrite the file if it is previously present.

Saving JSON file to iPhone

I want save json file from server each time, when user have internet connection to use it when iPhone doesnt have internet connection. But it doesn't working. Here is my code:
- (void)writeJsonToFile
{
//applications Documents dirctory path
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
//live json data url
NSString *stringURL = #"http://volodko.info/ic/json.php";
NSURL *url = [NSURL URLWithString:stringURL];
NSData *urlData = [NSData dataWithContentsOfURL:url];
//attempt to download live data
if (urlData)
{
NSString *filePath = [NSString stringWithFormat:#"%#/%#", documentsDirectory,#"data.json"];
[urlData writeToFile:filePath atomically:YES];
}
//copy data from initial package into the applications Documents folder
else
{
//file to write to
NSString *filePath = [NSString stringWithFormat:#"%#/%#", documentsDirectory,#"data.json"];
//file to copy from
NSString *json = [ [NSBundle mainBundle] pathForResource:#"data" ofType:#"json" inDirectory:#"html/data" ];
NSData *jsonData = [NSData dataWithContentsOfFile:json options:kNilOptions error:nil];
//write file to device
[jsonData writeToFile:filePath atomically:YES];
}
}
try this . . .
- (void)writeJsonToFile
{
//applications Documents dirctory path
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
//live json data url
NSString *stringURL = #"http://volodko.info/ic/json.php";
NSURL *url = [NSURL URLWithString:stringURL];
NSData *urlData = [NSData dataWithContentsOfURL:url];
//attempt to download live data
if (urlData)
{
NSString *filePath = [documentsDirectory stringByAppendingPathComponent:#"data.json"];
[urlData writeToFile:filePath atomically:YES];
}
//copy data from initial package into the applications Documents folder
else
{
//file to write to
NSString *filePath = [documentsDirectory stringByAppendingPathComponent:#"data.json"];;
//file to copy from
NSString *json = [ [NSBundle mainBundle] pathForResource:#"data" ofType:#"json" inDirectory:#"html/data" ];
NSData *jsonData = [NSData dataWithContentsOfFile:json options:kNilOptions error:nil];
//write file to device
[jsonData writeToFile:filePath atomically:YES];
}
}
This works for me. Read the AFJSONRequestOperation guide. The code also checks if the json-file already have been cached.
NSString *path = #"http://volodko.info/ic/json.php";
NSURL *url = [[NSURL alloc] initWithString:path];
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url];
id cachedJson = [[NSUserDefaults standardUserDefaults] valueForKey:path];
if (cachedJson) {
[self didUpdateJSON:cachedJson];
} else {
AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
[self didUpdateJSON:JSON];
dispatch_async(dispatch_get_main_queue(), ^{
[[NSUserDefaults standardUserDefaults] setObject:JSON forKey:path];
[[NSUserDefaults standardUserDefaults] synchronize];
});
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {
NSLog(#"Request Failed with Error: %#, %#", error, error.userInfo);
}];
[operation start];
}
Fetch data from JSON parser and store it in an array. After that you can add it to a SQLite database.
You should create path in proper way
replace this
NSString *filePath = [NSString stringWithFormat:#"%#/%#", documentsDirectory,#"data.json"];
with
NSString *filePath = [documentsDirectory stringByAppendingPathComponent:#"data.json"];
Anton , fetch the json data and store in the nsmutable array at the first time you Array hold the data when u run again ur array not a nil but replay the data to the second time ... and another way to store the data in local database...if u r needed to store the data..
but ur problem is solve for first one..ok best of luck..
Try using NSUserDefaults instead of writing this small JSON text to a file
- (void)writeJsonToFile
{
NSString *jsonString;
NSString *stringURL = #"http://volodko.info/ic/json.php";
NSURL *url = [NSURL URLWithString:stringURL];
NSData *urlData = [NSData dataWithContentsOfURL:url];
if (urlData)
{
// JSON successfully downloaded, store it to user defaults
jsonString = [[NSString alloc] initWithData:urlData encoding:NSUTF8StringEncoding];
[[NSUserDefaults standardUserDefaults] setValue:jsonString forKey:#"jsonString"];
}
else
{
// no urlData, using stored JSON
jsonString = [[NSUserDefaults standardUserDefaults] valueForKey:#"jsonString"];
}
}
possibly even better:
- (NSString *)getJSON
{
<the code above>
return jsonString;
}
and then use it in other functions as:
NSString *jsonString = [self getJSON];

NSFileManager Not Saving

I've been trying to use NSFileManager to cache images to the Cache directory of my sandboxed app. Unfortunately, my code doesn't seem to work.
- (BOOL)saveImageToCacheFolder
{
NSFileManager *filemgr = [NSFileManager defaultManager];
NSString *cachePath = [[[filemgr URLsForDirectory:NSCachesDirectory inDomains:NSUserDomainMask] lastObject] absoluteString];
NSString *fullpath = [cachePath stringByAppendingPathComponent:#"test.jpg"];
NSURL *imageURL = [FlickrFetcher urlForPhoto:self.photoData format:FlickrPhotoFormatLarge];
NSData *imageData = [NSData dataWithContentsOfURL:imageURL];
BOOL success = false;
if (imageData != nil) {
success = [imageData writeToURL:[NSURL URLWithString:fullpath] atomically:true];
if (!success) NSLog(#"Did Not Managed to save the image");
}
return success;
}
Here is what I am trying to do. First, get the default NSFileManager. Second, get the relative path to the cache directory of my app. Third, append the name of my file (here i just wrote test for now). Fourth, convert my image to NSData. Fourth, write the NSData object to the specified path.
edit: added if statement for checking if the imageData is nil
Try this:
NSArray *myPathList = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *cachePath = [myPathList objectAtIndex:0];
NSString *fullpath = [cachePath stringByAppendingPathComponent:#"test.jpg"];
NSURL *imageURL = [FlickrFetcher urlForPhoto:self.photoData format:FlickrPhotoFormatLarge];
NSData *imageData = [NSData dataWithContentsOfURL:imageURL];
if (imageData != nil) {
success = [imageData writeToURL:[NSURL fileURLWithPath:fullpath] atomically:YES];
if (!success) NSLog(#"Did Not Managed to save the image");
}

iOS download sqlite database and replace existing one

I have to download the database and replace existing one in the sandbox:
Here's is the presumable way to do that:
DBHelpers *help=[[DBHelpers alloc] init];
NSString *targetPath=[[help DocumentsDirectory] stringByAppendingPathComponent:DATABASE_NAME];
NSLog(#"Target path: %#", targetPath);
NSFileManager *fileManager=[NSFileManager defaultManager];
//if([fileManager fileExistsAtPath:targetPath])
//{
// NSLog(#"Exists");
// return;
}
NSString *sourcePath=[help PathForResource:DATABASE_NAME];
NSLog(#"SourcePath path: %#", sourcePath);
NSError *error;
NSData *data=[NSData dataWithContentsOfURL:[NSURL URLWithString:#"www.hello.com/mydb.sqlite"]];
[data writeToFile:targetPath atomically:NO];
// [fileManager copyItemAtPath:sourcePath toPath:targetPath error:&error];
NSLog(#"Error %#", error);
Consider these steps:
NSData *fetchedData = [NSData dataWithContentsOfURL:[NSURL URLWithString:#"http://www.myserver.com/files/DBName.sqlite"]]];
NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDire ctory, NSUserDomainMask, YES) lastObject];
NSString *filePath = [documentsPath stringByAppendingPathComponent:#"DBName.sqlite"];
[fetchedData writeToFile:filePath atomically:YES];
from iphonedevsdk forum thread.

NSData writeToFile not working

I cant seem to get nsdata to write to a file. Any ideas what i may be doing wrong. Thanks in advance.
NSString* filename = #"myfile.txt";
NSString *applicationDocumentsDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *storePath = [applicationDocumentsDir stringByAppendingPathComponent:filename];
if ([fileManager fileExistsAtPath:applicationDocumentsDir])
NSLog(#"applicationDocumentsDir exists"); // verifies directory exist
NSData *data = [NSData dataWithContentsOfURL:URL];
if (data) {
NSString *content = [[NSString alloc] initWithBytes:[data bytes]
length:[data length] encoding: NSUTF8StringEncoding];
NSLog(#"%#", content); // verifies data was downloaded correctly
NSError* error;
[data writeToFile:storePath options:NSDataWritingAtomic error:&error];
if(error != nil)
NSLog(#"write error %#", error);
}
I keep getting the error
"The operation couldn’t be completed. No such file or directory"
Try
NSString *storePath = [applicationDocumentsDir stringByAppendingPathComponent:#"myfile.txt"];
And
if ([[NSFileManager defaultManager] fileExistsAtPath:storePath])
NSLog(#"applicationDocumentsDir exists");
To get more information, you can use
writeToFile:options:error:
instead of
writeToFile:atomically:
but you need to create all the subdirectories in the path prior to doing the write. Like this:
// if the directory does not exist, create it...
if ( [fileManager fileExistsAtPath:dir_path] == NO ) {
if ( [fileManager createDirectoryAtPath:dir_path withIntermediateDirectories:NO attributes:NULL error:&error] == NO ) {
NSLog(#"createDirectoryAtPath failed %#", error);
}
}

Resources