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.
Related
I have PDFs in my project. I want to give feature to download that file to mobile directory and load it with other apps.
You can directly used your image if it is in app bunldle like,
UIImage *img = [UIImage imageNamed:#"Amy.png"];
If you want to load pdf in webview from app bundle then you can do something like,
NSString *path = [[NSBundle mainBundle] pathForResource:#"yourPdfName" ofType:#"pdf"];
NSURL *url = [NSURL fileURLWithPath:path];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[webView loadRequest:request];
In short if you have files available in app bundle then you not need to copy it to documentDirectory because it will use double memory, you can direct used it from bundle.
NSError *error;
NSFileManager *fileManager = [NSFileManager defaultManager];
//NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDir = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)objectAtIndex:0]stringByAppendingPathComponent:#"/RTOFiles"];;
if (![[NSFileManager defaultManager] fileExistsAtPath:documentsDir])
[[NSFileManager defaultManager] createDirectoryAtPath:documentsDir withIntermediateDirectories:NO attributes:nil error:&error];
NSString *pdfName = #"form_1.pdf";
NSString *docPdfFilePath = [documentsDir stringByAppendingPathComponent: pdfName];
//Using NSFileManager we can perform many file system operations.
BOOL success = [fileManager fileExistsAtPath: docPdfFilePath];
if (!success) {
NSString *samplePdfFile = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent: pdfName];
success = [fileManager copyItemAtPath: samplePdfFile toPath: docPdfFilePath error: &error];
if (!success)
// NSAssert1(0, #"Failed to copy file ‘%#’.", [error localizedDescription]);
NSLog(#"Failed to copy %# file, error %#", pdfName, [error localizedDescription]);
else {
NSLog(#"%# File copied to %#", pdfName,documentsDir);
}
}
else{
NSLog(#"File already Exists !");
}
I am trying to upload sqlite file on iCloud. I am using NSFileCoortinator for coping the file from one file to another file but schema of sqlite file is only get copied, I am not getting data in sqlite file….Also sometimes the data is appearing in the sqlite file on iCloud. I don’t understand why this is happening. Is this sqlite file issue or I did wrong in code. If anyone has solution please help me out.
-(void)uploadFile
{
//-------code for uploading data to icloud
NSArray *paths =
NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory,
NSUserDomainMask, YES);
NSString *applicationSupportDirectory = [paths firstObject]
NSString *str=[NSString stringWithFormat:#"%#/XMPPMessageArchiving.sqlite",applicationSupportDirectory]; //copy this file
NSString *fileName = [NSString stringWithFormat:#"XMPPMessageArchiving.sqlite"];
NSURL *ubiq = [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil];
NSFileCoordinator *coordinator = [[NSFileCoordinator alloc] initWithFilePresenter:nil];
NSURL *fromURL = [NSURL fileURLWithPath:str];
NSURL *toURL = [[ubiq URLByAppendingPathComponent:#"Documents"]
URLByAppendingPathComponent:fileName];;
[coordinator coordinateReadingItemAtURL:fromURL options:0 writingItemAtURL:toURL options:NSFileCoordinatorWritingForReplacing error:nil byAccessor:^(NSURL *newReadingURL, NSURL *newWritingURL)
{
NSError *error=nil;
NSData *data = [[NSFileManager defaultManager] contentsAtPath:fromURL.path];
//if file is already present on icloud replace that file with new file
BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:newWritingURL.path];
if (fileExists)
{
[[NSFileManager defaultManager] removeItemAtPath:toURL.path error:NULL];
}
BOOL isCopied= [[NSFileManager defaultManager] copyItemAtPath:newReadingURL.path toPath:newWritingURL.path error:nil];
NSLog(#"file copied= %d",isCopied);
}];
}
The value for file copied is always 1 but still data is not available.
I am trying get NSData of an own file.
My code is as follow, but NSData returned is always nil… (As you can see, I check if the file exists previously)
if ([[NSFileManager defaultManager] fileExistsAtPath:path]){
NSData * data = [[NSFileManager defaultManager] contentsAtPath:path];
}
Any idea? Thanks!
It's possible that path is a folder, in which case fileExistsAtPath will return YES, but no data can be read.
You can add some extra debugging by reading the data as follows:
NSError* error = nil;
NSData* data = [NSData dataWithContentsOfFile:path options:0 error:&error];
NSLog(#"Data read from %# with error: %#", path, error);
The log output will display the actual error that occurred.
Use This code it works
NSString *path = [pathURL filePath];
if([[NSFileManager defaultManager] fileExistsAtPath:path)
{
NSData *data = [[NSFileManager defaultManager] contentsAtPath:path];
}
else
{
NSLog(#"File not exits");
}
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];
EDIT: Solution at the end of the post
I'm having trouble creating a subdirectory of NSCachesDirectory and adding an NSData object to it. I've referred to multiple SO posts related to this but when I debug my code, it tells me that the NSData file in the folder doesn't exist. My code:
NSURL *photoURL = [FlickrFetcher urlForPhoto:self.singlePhotoDictionary
format:FlickrPhotoFormatLarge];
NSData *URLToData = [NSData dataWithContentsOfURL:photoURL];
NSString *cacheDirectory = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *newDirectory = [cacheDirectory stringByAppendingPathComponent:#"Photos"];
BOOL isDir = NO;
NSError *error;
if (! [[NSFileManager defaultManager] fileExistsAtPath:newDirectory isDirectory:&isDir] && isDir == NO)
{
[[NSFileManager defaultManager]createDirectoryAtPath:newDirectory withIntermediateDirectories:NO attributes:nil error:&error];
}
NSString *filePath = [newDirectory stringByAppendingPathComponent:#"thePhotos.jpg"];
NSLog(#"%#", filePath);
//[URLToData writeToFile:filePath atomically:NO];
[[NSFileManager defaultManager] createFileAtPath:filePath contents:URLToData attributes:nil];
NSData *theData = [[NSFileManager defaultManager] contentsAtPath:filePath];
NSArray *contentsInManager = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:newDirectory error:nil];
theData and contentsInManager turn out to be:
theData NSData * 0x00000000
contentsInManager NSArray * 0x00000000
Any help here? The subdirectory exists but the file won't be created inside of it.
As a side question: When do we need to make our own instance of NSFileManager as opposed to using the defaultManager?
Thanks in advance!
SOLUTION: After trial and error, I tried deleting the subdirectory and recreating it. Once I did, the file was able to write to the subdirectory.