writeToFile fails with error = null - ios

I have an app running in the XCode simulator (v6.4); this is the pertinent code:
NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
// read the file back into databuffer...
NSFileHandle *readFile = [NSFileHandle fileHandleForReadingAtPath:[documentsPath stringByAppendingPathComponent: #"Backup.txt"]];
NSData *databuffer = [readFile readDataToEndOfFile];
[readFile closeFile];
// compress the file
NSData *compressedData = [databuffer gzippedData] ;
// Write to disk
NSString *outputPath = [NSString stringWithFormat:#"%#/%#%#.zip", documentsPath, venueName, strDate];
_BackupFilename = fileName; // save for upload
NSFileHandle *outputFile = [NSFileHandle fileHandleForWritingAtPath:outputPath];
NSError *error = nil;
// write the data for the backup file
BOOL success = [compressedData writeToFile: outputPath options: NSDataWritingAtomic error: &error];
if (error == nil && success == YES) {
NSLog(#"Success at: %#",outputPath);
}
else {
NSLog(#"Failed to store. Error: %#",error);
}
[outputFile closeFile];
I'm trying to create a backup of a file by taking the file, compressing it and then writing it out. I get an error Failed to store. Error: (null)); why is it failing without returning the error code?

There are quite a few things wrong here. To start. change your if statement to:
if (success) {
Never explicitly compare a BOOL value to YES or NO.
You also never use outputFile so remove that code. It may interfere with the call to writeToFile:.
And there's no point in using the file handle to read the data. Just use NSData dataWithContentsOfFile:.
And don't build paths using stringWithFormat:.
Overall, I would write your code as:
NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
// read the file back into databuffer...
NSString *dataPath = [documentsPath stringByAppendingPathComponent:#"Backup.txt"]];
NSData *databuffer = [NSData dataWithContentsOfFile:dataPath];
// compress the file
NSData *compressedData = [databuffer gzippedData];
// Write to disk
NSString *outputName = [NSString stringWithFormat:#"%#%#.zip", venueName, strDate];
NSString *outputPath = [documentsPath stringByAppendingPathComponent:outputName];
// write the data for the backup file
NSError *error = nil;
BOOL success = [compressedData writeToFile:outputPath options:NSDataWritingAtomic error:&error];
if (success) {
NSLog(#"Success at: %#",outputPath);
} else {
NSLog(#"Failed to store. Error: %#",error);
}
Since success is still NO and error is still nil, then most likely this means that compressedData is nil. This probably means that databuffer is nil which means that there is no file named Backup.txt (case matters) in the Documents folder.

Related

iOS - writeToFile from NSData completion handler

I am getting bytes of a file from a webservice, my goal is to get these bytes, put them into NSData and then write into a file, once the writeToFile is 100% complete, I would then display the file (its a PDF, can be up to 6 pages) in QLPreviewController.
I am able to get the bytes from the webservice and put them into NSData like so:
NSArray *byteArray = [dataSource.areaData GetPDFFileData:[NSString stringWithFormat:#"%#",encodedUrlStr]];
NSData *data;
for (NSDictionary *dict in byteArray) {
NSString *base64 = dict[#"data"];
data = [[NSData alloc] initWithBase64EncodedString:base64 options:0];
}
Now I am trying to write the file like so:
if (data)
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
filePath = [NSString stringWithFormat:#"%#/%#", documentsDirectory,PDFFile];
[data writeToFile:filePath atomically:YES];
}
Now what I am trying to do is have some sort of completion handler so nothing else happens until the file is completely written. What would be the best way to do this?
I am also starting to look into NSFileHandle, would that be a better solution?
use NSFilePresenter to monitor for changes to the file
and use a NSFileCoordinator to write to it
in mock code:
NSFilePresenter *p = [NSFilePresenter presenterWithFile:f];
[p signupForChangeNotificationsOrSetDelegateOrWhatever....];
//write
NSFileCoordinator *c = [NSFileCoordinator coordinatorWithPresenter:p];
[c coordinate writeData....]
... called back by p cause we changed
No need to worry about completion if this runs in main queue it's serial , but it's better to save in background queue and read content to verify and present in main Queue
DispatchQueue.global(qos: .background).async {
print("This is run on the background queue")
if (![[NSFileManager defaultManager] fileExistsAtPath:filePath])
{
NSLog(#"not exists");
NSData *fileContents = [#"" dataUsingEncoding:NSUTF8StringEncoding];
[[NSFileManager defaultManager] createFileAtPath:filePath
contents:fileContents
attributes:nil];
}
else
{
NSLog(#"exists");
}
NSFileHandle *myHandle = [NSFileHandle fileHandleForWritingAtPath:filePath];
[myHandle seekToEndOfFile];
NSString*strTowrite=[NSString stringWithFormat:#"%# || %# --- %# \r\n",dt,acion,name];
[myHandle writeabilityHandler];
[myHandle writeData:[strTowrite dataUsingEncoding:NSUTF8StringEncoding]];
DispatchQueue.main.async {
NSString*content=[[NSString alloc] initWithContentsOfFile:filePath
encoding:NSUTF8StringEncoding
error:&error];
if(content)
{
NSLog(#"content is : %# Err : %#",content,error);
// [self sendfile];
}
else
{
NSLog(#"Failed to store the file. Error = %#", error);
}
}
}

dataWithContentsOfFile return null

NSString *path = dict[#"fileURL"];
NSData *imageData = [NSData dataWithContentsOfFile:path];
imageData is null
dict[#"fileURL"] =
/var/mobile/Containers/Data/Application/0906AB53-CE1F-45EF-8E00-9D0B7C98956C/Documents/ccc/image/1446625127.png
I download the device container and the image did exist.
What's wrong?
It's failed to retrieve your file. Use -dataWithContentsOfFile:options:error: to find why it is failed.
NSError* error = nil;
NSString *path = dict[#"fileURL"];
NSData *data = [NSData dataWithContentsOfFile:path options: 0 error: &error];
if (data == nil)
{
NSLog(#"Failed to read file, error %#", error);
}
else
{
// parse the value
}
I thing you should need to use [NSFileManager defaultManager] to store and fetch the image in your application storage instead of writing static path.
Static path is ok withing the simulator but in the real environment you should need to have the actual path. So [NSFileManager defaultManager] will help you.
if([[NSFileManager defaultManager] fileExistsAtPath:filepath)
{
NSData *data = [[NSFileManager defaultManager] contentsAtPath:filepath];
}
else
{
NSLog(#"File not exits");
}
In filepath you need to pass only your folder and file name. not full path like yours.
IE.
filepath = "Documents/ccc/image/1446625127.png";
NOTE:
This is not a actual answer. This will help you to manage the image into your application storage.

How to rename files/folders from document folder programmatically in iOS

I am working on functionality to save video files in document folder of application in iOS.
How to rename some files programmatically?
try this code :
NSError * err = NULL;
NSFileManager * fm = [[NSFileManager alloc] init];
BOOL result = [fm moveItemAtPath:#"/tmp/test.tt" toPath:#"/tmp/dstpath.tt" error:&err];
if(!result)
NSLog(#"Error: %#", err);
other wise use this method to rename file
- (void)renameFileWithName:(NSString *)srcName toName:(NSString *)dstName
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *filePathSrc = [documentsDirectory stringByAppendingPathComponent:srcName];
NSString *filePathDst = [documentsDirectory stringByAppendingPathComponent:dstName];
NSFileManager *manager = [NSFileManager defaultManager];
if ([manager fileExistsAtPath:filePathSrc]) {
NSError *error = nil;
[manager moveItemAtPath:filePathSrc toPath:filePathDst error:&error];
if (error) {
NSLog(#"There is an Error: %#", error);
}
} else {
NSLog(#"File %# doesn't exists", srcName);
}
}
There is no Direct API to rename the file . Though when you move the file from one place to another place, if that file in destination path not exists then iOS will create the file in the given name. For file you can just give the New name of your file, how it should be displayed/referenced.
you could check this answer. Good luck!

save image to subfolder of /library/Application Support/bundleID_name/... iOS

The following code works without error or exception - but still, it does not do what it should ! I wanted to save an image into the iOS library/Application Support folder. More precisely, the image should be placed into a /library/Application Support/bundleID_name/subfolder/ (and the subfolder being called "location1").
If I check the functionality with the iOS-Simulator, I can see the creation of the subfolder (i.e. .../library/Application Support/bundleID_name/location1/). Also the function "saveImage" works without exception. But there is no image being saved !!!! (i.e.the image-file is missing and the folder remains empty) !!
What could be the mistake ??
Here is my code with the call of two functions (see code below):
UIImage *in_image = [UIImage imageNamed:#"template009c.jpg"];
NSString *locDirectoryName = #"location1";
NSURL *LocationDirectory = [self appendLocationToApplicationDirectory:locDirectoryName];
[self saveImage:in_image :#"image1" :LocationDirectory];
With the corresponding function-Nr1:
- (NSURL*)appendLocationToApplicationDirectory:(NSString*)locationDirName
{
NSString* appBundleID = [[NSBundle mainBundle] bundleIdentifier];
NSFileManager*fm = [NSFileManager defaultManager];
NSURL* dirPath = nil;
// Find the application support directory in the home directory.
NSArray* appSupportDir = [fm URLsForDirectory:NSApplicationSupportDirectory
inDomains:NSUserDomainMask];
if ([appSupportDir count] > 0) {
// Append the bundle ID and the location-Foldername to the URL for the Application Support directory
dirPath = [[[appSupportDir objectAtIndex:0] URLByAppendingPathComponent:appBundleID] URLByAppendingPathComponent:locationDirName];
// If the directory does not exist, this method creates it.
// This method call works in OS X 10.7 and later only.
NSError* theError = nil;
if (![fm createDirectoryAtURL:dirPath withIntermediateDirectories:YES attributes:nil error:&theError]) {
// Handle the error.
NSLog(#"%#", theError.localizedDescription);
return nil;
}
else {
// Mark the directory as excluded from iCloud backups
if (![dirPath setResourceValue:#YES
forKey:NSURLIsExcludedFromBackupKey
error:&theError]) {
NSLog(#"Error excluding %# from iCloud backup %#", [dirPath lastPathComponent], theError.localizedDescription);
}
else {
NSLog(#"Location Directory excluded from iClud backups");
}
}
}
return dirPath;
}
And function Nr2:
//saving an image
- (void)saveImage:(UIImage*)image :(NSString*)imageName :(NSURL*)pathName {
NSData *imageData = UIImagePNGRepresentation(image); //convert image into .png format.
NSFileManager *fileManager = [NSFileManager defaultManager];
// NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
// NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *LocationDirectory = [pathName absoluteString];
NSString *fullPath = [LocationDirectory stringByAppendingPathComponent:[NSString stringWithFormat:#"%#.png", imageName]];
/***** THE FOLLOWING LINE DOES NOT SEEM TO DO WHAT IT IS SUPPOSED TO *******/
[fileManager createFileAtPath:fullPath contents:imageData attributes:nil];
/**** I also tried without the FileManager, but same problem - no file written... ***/
// [imageData writeToFile:fullPath atomically:NO];
NSLog(#"image saved");
}
By the way, getting the "fullPath" with the XCode-Debugger, I get:
"fullPath NSPathStore2 * #"file:/Users/username/Library/Application%20Support/iPhone%20Simulator/7.1/Applications/2BCC3345-9M55F-4580-A1E7-6694E33456777/Library/Application%20Support/bundleID_name/image1.png" 0x09d50950
Doesn't that also seem correct ?? But why is [fileManager createFileAtPath:fullPath contents:imageData attributes:nil]; not performing ???
This:
"fullPath NSPathStore2 * #"file:/Users/username/Library/Application%20Support/iPhone%20Simulator/7.1/Applications/2BCC3345-9M55F-4580-A1E7-6694E33456777/Library/Application%20Support/bundleID_name/image1.png" 0x09d50950
is not a valid path, it's a URL path but stored in a string. If you are going to use URL's then use ULRs rather than trying to convert to a string:
[imageData writeToURL:pathName atomically:YES];
(preferably naming the parameter as pathURL) and if you want to use paths then don't use a URL at any stage.
Also, where an API method returns an error or status flag, check it in the code as standard.
I'm pretty sure you can't save an image on a path you specify. You can save images on the gallery or in DocumentDirectory. This should be the code to save an image on the DocumentDirectory:
NSString *imgName=[#"imgname.png"];
[[NSUserDefaults standardUserDefaults]setValue:imgName forKey:#"imageName"];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *savedImagePath = [documentsDirectory stringByAppendingPathComponent:imgName];
UIImage *image = imageView.image; // imageView is my image from camera
NSData *imageData = UIImagePNGRepresentation(image);
[imageData writeToFile:savedImagePath atomically:NO];

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