NSFileHandle fileHandleForWritingAtPath: return null! - cocoa-touch

my iPad app has a small download facility, for which I want to append the data using an NSFileHandle. The problem is the creation call only returns null file handles. What could be the problem? Here is the three lines of code that are supposed to create my file handle:
NSString *applicationDocumentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
self.finalPath = [applicationDocumentsDirectory stringByAppendingPathComponent: self.fileName];
NSFileHandle *output = [NSFileHandle fileHandleForWritingAtPath:self.finalPath];
I checked the file path, and I could see nothing wrong.
TYIA

fileHandleForWritingAtPath is not a “creation” call. The documentation explicitly states: “Return Value: The initialized file handle, or nil if no file exists at path” (emphasis added). If you wish to create the file if it does not exist, you’d have to use something like this:
NSFileHandle *output = [NSFileHandle fileHandleForWritingAtPath:self.finalPath];
if(output == nil) {
[[NSFileManager defaultManager] createFileAtPath:self.finalPath contents:nil attributes:nil];
output = [NSFileHandle fileHandleForWritingAtPath:self.finalPath];
}
If you want to append to the file if it already exists, use something like [output seekToEndOfFile]. Your complete code would then look as follows:
NSString *applicationDocumentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
self.finalPath = [applicationDocumentsDirectory stringByAppendingPathComponent: self.fileName];
NSFileHandle *output = [NSFileHandle fileHandleForWritingAtPath:self.finalPath];
if(output == nil) {
[[NSFileManager defaultManager] createFileAtPath:self.finalPath contents:nil attributes:nil];
output = [NSFileHandle fileHandleForWritingAtPath:self.finalPath];
} else {
[output seekToEndOfFile];
}

Get documents directory path
+(NSURL *)getDocumentsDirectoryPath
{
return [[[NSFileManager defaultManager]URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask]lastObject];
}
Save text to end of the file
if file doesnt exist create it and write data
+(void)saveText:(NSString *)textTobeSaved atPath:(NSString*)fileName
{
NSString *filePath = [NSString stringWithFormat:#"%#.text",fileName];
NSString *path = [[self getDocumentsDirectoryPath].path
stringByAppendingPathComponent:filePath];
NSFileHandle *fileHandler = [NSFileHandle fileHandleForWritingAtPath:path];
if(fileHandler == nil) {
[[NSFileManager defaultManager] createFileAtPath:path contents:nil attributes:nil];
fileHandler = [NSFileHandle fileHandleForWritingAtPath:path];
} else {
textTobeSaved = [NSString stringWithFormat:#"\n-----------------------\n %#",textTobeSaved];
[fileHandler seekToEndOfFile];
}
[fileHandler writeData:[textTobeSaved dataUsingEncoding:NSUTF8StringEncoding]];
[fileHandler closeFile];
}
get text from file with specified filename
+(NSString *)getTextFromFilePath:(NSString *)fileName
{
NSString *filePath = [NSString stringWithFormat:#"%#.text",fileName];
NSString *path = [[self getDocumentsDirectoryPath].path
stringByAppendingPathComponent:filePath];
NSLog(#"%#",path);
if(path!=nil)
{
NSString *savedString = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
return savedString;
}else{
return #"";
}
}
Delete file
+(void)deleteFile:(NSString *)fileName
{
NSString *filePath = [NSString stringWithFormat:#"%#.text",fileName];
NSString *path = [[self getDocumentsDirectoryPath].path
stringByAppendingPathComponent:filePath];
NSFileHandle *fileHandler = [NSFileHandle fileHandleForWritingAtPath:path];
if(fileHandler != nil) {
[[NSFileManager defaultManager]removeItemAtPath:path error:nil];
}
}

Related

iOS: write data to json file programatically

My json file look like this:
{
"images": [
"straight up kick.png",
"women kick.png",
"Taekwondo Kanji vertical.png",
"face kick3.png",
"flexibility.png",
"Punch.png",
"hook kick.png",
"front kick 2.png"
]
}
i am reading above json programmatically like below:
NSString *path = [[NSBundle mainBundle] pathForResource:#"generated" ofType:#"json"];
NSData *data = [NSData dataWithContentsOfFile:path];
NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];
NSMutableArray * jsonimages = [dict objectForKey:#"images"];
NSLog(#"images %#", jsonimages);
i want to add more items to array named as jsonimages by writing to json file programmatically.
Json file name is generated.json.
Any help would be appreciated.
- (void)writeStringToFile:(NSString*)aString {
// Build the path, and create if needed.
NSString* filePath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString* fileName = #"generated.json";
NSString* fileAtPath = [filePath stringByAppendingPathComponent:fileName];
if (![[NSFileManager defaultManager] fileExistsAtPath:fileAtPath]) {
[[NSFileManager defaultManager] createFileAtPath:fileAtPath contents:nil attributes:nil];
}
// The main act...
[[aString dataUsingEncoding:NSUTF8StringEncoding] writeToFile:fileAtPath atomically:NO];
}
- (NSString*)readStringFromFile {
// Build the path...
NSString* filePath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString* fileName = #"generated.json";
NSString* fileAtPath = [filePath stringByAppendingPathComponent:fileName];
// The main act...
return [[NSString alloc] initWithData:[NSData dataWithContentsOfFile:fileAtPath] encoding:NSUTF8StringEncoding];
}

Using apples suggested code isnt excluding files from icloud backup

I have an app that has been rejected 3 times due to icloud backup issues. Apple have written back to say that I need to use there bit of code to exclude the files from being backed up. However this isnt working and i am at wits end.
Here is the code i've used
- (BOOL)downloadFile:(NSString *)fileURI targetFolder:(NSString *)targetFolder targetFilename:(NSString *) targetFilename{
#try{
NSError *error = nil;
NSURL *url = [NSURL URLWithString:fileURI];
if(![url setResourceValue:#"YES" forKey:NSURLIsExcludedFromBackupKey error:&error]){
NSLog(#"KCDM: Error excluding %# from backup %#", fileURI, error);
}else{
NSData *urlData = [NSData dataWithContentsOfURL:url];
if ( urlData )
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *dataPath = [documentsDirectory stringByAppendingString:targetFolder];
NSError *error = nil;
if(![[NSFileManager defaultManager] fileExistsAtPath:dataPath]){
[[NSFileManager defaultManager] createDirectoryAtPath:dataPath withIntermediateDirectories:YES attributes:nil error:&error];
}
NSString *filePath = [NSString stringWithFormat:#"%#/%#%#", documentsDirectory,targetFolder,targetFilename];
return [urlData writeToFile:filePath atomically:YES];
}
}
}
#catch(NSException * e){
NSLog(#"Error download: %#",e);
}
return false;
}
what am i doing wrong?
You try to set NSURLIsExcludedFromBackupKey for the http://-Url you download from the web. That won't work.
You have to set this key-value pair for the actual file that is saved on the device.
Additionally you are not supposed to set this value to the string #"YES", you must use a NSNumber object representing the boolean value YES.
For example:
NSString *filePath = [NSString stringWithFormat:#"%#/%#%#", documentsDirectory,targetFolder,targetFilename];
if ([urlData writeToFile:filePath atomically:YES]) {
// did write correctly
NSURL *fileURL = [NSURL fileURLWithPath:filePath];
if(![fileURL setResourceValue:#YES forKey:NSURLIsExcludedFromBackupKey error:&error]){
NSLog(#"KCDM: Error excluding %# from backup %#", fileURI, error);
return NO;
}
// could set NSURLIsExcludedFromBackupKey
return YES;
}
// could not write to file
return NO;

UIImage gives nil

I'm quite new to iOS development. My app gets a file over a network, writes it as image.png and later on reads and displays the image. However, the display part is not working as my UIImage object is always set to nil (on the iOS simulator). I've tried implementing other answers from stackoverflow, but no luck.
Here's my code to save the file:
//inside utility class for model
NSFileHandle * handle = nil;
//For first packet of new file request
if(CountFileParts == 1)
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *appFile = [documentsDirectory stringByAppendingPathComponent:#"image.png"];
NSLog(#"%#",appFile);
handle = [NSFileHandle fileHandleForWritingAtPath:appFile];
if(handle == nil)
{
[[NSFileManager defaultManager] createFileAtPath:appFile contents:nil attributes:nil];
handle = [NSFileHandle fileHandleForWritingAtPath:appFile];
}
}
//For other incoming packets of the same request
else
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *appFile = [documentsDirectory stringByAppendingPathComponent:#"image.png"];
//NSLog(#"%#",appFile);
handle = [NSFileHandle fileHandleForUpdatingAtPath:appFile];
[handle seekToEndOfFile];
//NSLog(#"Writing continue in new file");
}
if(handle == nil)
NSLog(#"handle nil");
NSData * data = [str dataUsingEncoding:NSUTF8StringEncoding];
[handle writeData:data];
[handle closeFile];
if(index != -1 && index!= NSNotFound)
{
NSLog(#"Inside Bool");
self.isPlotReady = YES;//kvo in view-controller as shown below
self.isPlotReady = NO;
}
Here's my code to load the image file:
-(void) observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if([keyPath isEqualToString:#"isPlotReady"])
{
self.isReady = [[change objectForKey:NSKeyValueChangeNewKey] boolValue];
[self updateUI];
}
}
-(void) updateUI
{
if(self.isReady)
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
[self lsOwnDirectory:documentsDirectory];
NSString *appFile = [documentsDirectory stringByAppendingPathComponent:#"image.png"];
//NSLog(#"%#",appFile);
UIImage *img = [UIImage imageWithContentsOfFile:appFile];
if(img == nil)
NSLog(#"Couldn't find image");
else
{
UIImageView *imageView = [[UIImageView alloc] initWithImage:img] ;
[self.view addSubview:imageView];
}
}
}
//Prints Directory contents of input directory
- (void) lsOwnDirectory:(NSString *) currentpath {
NSError * error = [[NSError alloc] init];
NSFileManager *filemgr;
filemgr = [[NSFileManager alloc] init];
//currentpath = [filemgr currentDirectoryPath];
NSLog(#"Current Directory Path : %#",currentpath);
NSArray * files = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:currentpath error: &error];
for(NSString * file in files){
NSLog(#"%#", file);
}
}
It alway's prints "Couldn't find image" corresponding to the if statement, but I've seen the file is still there (lsOwnDirectory prints directory contents). Maybe I'm doing something basic wrong here. Thanks in advance.

Saving images to a directory

Hi I want to save an image to a directory, I pass the NSData and do what I think will save the file in a directory I create but the problem is that it doesn't save. This is what I have so far. Why doesn't the initWithContentsOfURL:encoding:error: work, it returns null but the other method I used works? The main problem is WRITETOURL which returns a 0 which i think means that the information wasn't stored properly, any tips?
NSFileManager *fm = [[NSFileManager alloc] init];
NSArray * directoryPaths = [fm URLsForDirectory:NSCachesDirectory inDomains:NSUserDomainMask];
NSLog(#"%#", directoryPaths);
NSURL* dirPath = nil;
dirPath = [[directoryPaths objectAtIndex:0] URLByAppendingPathComponent:[NSString stringWithFormat:#"photos.jpeg"]];
NSError* theError = nil;
[fm createDirectoryAtURL:dirPath withIntermediateDirectories:YES attributes:nil error:&theError];
UIImage* photoToStore = [UIImage imageWithData:photoToSave];
NSString *pathContainingPhoto = [[NSString alloc] initWithFormat:#"%#.jpeg", UIImageJPEGRepresentation(photoToStore, 1.0)];
NSError *error = nil;
BOOL OK = [pathContainingPhoto writeToURL:dirPath atomically:YES encoding:NSUTF8StringEncoding error:&error];
NSLog(#"OK = %d", OK); //Returns 0
NSLog(#"%#", dirPath);
//WHY DOESNT THIS VERSION WORK?
// NSString *pathToFile = [[NSString alloc] initWithContentsOfURL:dirPath encoding:NSUTF8StringEncoding error:&error];
NSLog(#"%#", pathToFile);
NSString* pathToFile = [NSString stringWithContentsOfURL:dirPath encoding:nil error:nil];
NSArray *dirContents = [fm contentsOfDirectoryAtPath:pathToFile error:nil];
NSLog(#"%#", dirContents);
Do like this and int count in .h file and set its intial value count = 0; in viewDidLoad:
NSString *stringPath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)objectAtIndex:0]stringByAppendingPathComponent:[NSString stringWithFormat:#"Image_%d.png",count];
error = nil;
if (![[NSFileManager defaultManager] fileExistsAtPath:stringPath]) // removing item it already exuts
{
[[NSFileManager defaultManager] removeItemAtPath:stringPath error:&error];
}
if(photoToSave) // nsdata of image that u have
{
[photoToSave writeToFile:stringPath atomically:YES];
}
count++; // maintaining count of images

Reading fileModificationDate

How do I access the fileModificationDate
NSString *docsDir = [NSHomeDirectory() stringByAppendingPathComponent:
#"TempiPad"];
NSFileManager *localFileManager=[[NSFileManager alloc] init];
NSDirectoryEnumerator *dirEnum =
[localFileManager enumeratorAtPath:docsDir];
NSString *file;
// List all files in docsDir
while (file = [dirEnum nextObject]) {
NSLog(#"File = %#",file);
NSError *attributesError = nil;
NSDictionary *fileAttributes = [[NSFileManager defaultManager] attributesOfItemAtPath:file error:&attributesError];
NSString *fileModificationDate = [fileAttributes objectForKey:NSFileModificationDate];
NSLog(#"ModDate = %#",fileModificationDate);
}
}
This just outputs (null). Eventually I will want to compare the fileModificationDate for two files, so how will I do that?
IIRC, you need to append the filename to the directory path; something like:
while (file = [dirEnum nextObject]) {
NSLog(#"File = %#",file);
NSError *attributesError = nil;
file = [docsDir stringByAppendingPathComponent:file];
NSDictionary *fileAttributes = [[NSFileManager defaultManager] attributesOfItemAtPath:file error:&attributesError];
NSDate *fileModificationDate = [fileAttributes objectForKey:NSFileModificationDate];
NSLog(#"ModDate = %#",fileModificationDate);
}
}
And, as more tension said, NSFileModificationDate is an NSDate, not an NSString.
NSFileModificationDate returns an NSDate instance, not an NSString. See:
NSFileModificationDate