Store and Load File from URL - iphone

iPhone App
I am currently trying to understand how i can store a file from a URL to the documents directory and then read the file from the documents directory..
NSURL *url = [NSURL URLWithString:#"http://some.website.com/file"];
NSData *data = [NSData dataWithContentsOfURL:url];
NSString *applicationDocumentsDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
NSString *storePath = [applicationDocumentsDir stringByAppendingPathComponent:#"Timetable.ics"];
[data writeToFile:storePath atomically:TRUE];
I got this code from http://swatiardeshna.blogspot.com/2010/06/how-to-save-file-to-iphone-documents.html
I want to know if this is the correct way to do this and i want to know how i can load the file from the documents directory into an NSString..
Any help will be greatly appreciated.

What you have looks correct, to read that file back into a string use:
EDIT: (changed usedEncoding to encoding)
NSError *error = nil;
NSString *fileContents = [NSString stringWithContentsOfFile:storePath encoding:NSUTF8StringEncoding error:&error];
Of course you should change the string encoding type if you are using a specific encoding type, but UTF8 is likely correct.

If you're doing this on your main thread, then no it's not correct. Any sort of network connection should be done in the background so you don't lock up the interface. For that, you can create a new thread (NSThread, performSelectorInBackground:, NSOperation+NSOperationQueue) or schedule it on the run loop (NSURLConnection).

Related

How to email sqlite database of Iphone app from itself?

In my current app I am adding a data backup and restore feature.
User can create back up of database and can email it.
In restore feature user can import the database from email and can replace the current.
I am able to do create back up and restore of database file.
In restore I am just copying the file from my email to app Documents file replacing current one.
The problem is that in my code for backup of database, sqlite database is converted to NSData. I don't want to to be converted and need the exact sqlite file to be emailed.
Here is the code that I currently use to email sqlite database
-(void)backUpData
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *txtPath = [documentsDirectory stringByAppendingPathComponent:#"/DemoApp.sqlite"];
NSURL *newUrl = [[NSURL alloc] initWithString:
[txtPath stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding]];
NSData *sqliteData = [[NSData alloc] initWithContentsOfURL:newUrl];
//send sqliteData to email composer delegate to attach it as attachment
[self showPicker:sqliteData];
}
How I can email sqlite db without converting it to NSData?
Use dataWithContentsOfFile when creating the NSData object giving the path rather than a url. For example:
NSString *dbPath = [[NSBundle mainBundle] pathForResource:#"Pubs" ofType:#"db"];
NSData *myData = [NSData dataWithContentsOfFile:dbPath];
[mailComposeVC addAttachmentData:myData mimeType:#"application/x-sqlite3" fileName:#"Pubs.db"];

Rewriting problem while loggin in iPhone

i am using following code to log into a file...
NSData *dataToWrite = [[NSString stringWithString:#"log data"] dataUsingEncoding:NSUTF8StringEncoding];
NSString *docsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *path = [docsDirectory stringByAppendingPathComponent:#"fileName.txt"];
[dataToWrite writeToFile:path atomically:YES];
But when this method gets called again...it doest show the last entry...??
Could anyone suggest?
thanks
It is better you try using NSFileHandle , because the write operation to a file on NSData simply a convenience function and can not do a full fledged file operations like appending.

Load remote csv into CHCSVParser

I am using Dave DeLong's CHCSVParser to parse a csv. I can parse the csv locally, but I cannot get it load a remote csv file. I have been staring at my MacBook way too long today and the answer is right in front of me. Here is my code:
NSString *urlStr = [[NSString alloc] initWithFormat:#"http://www.somewhere.com/LunchSpecials.csv"];
NSURL *lunchFileURL = [NSURL URLWithString:urlStr];
NSStringEncoding encoding = 0;
CHCSVParser *p = [[CHCSVParser alloc] initWithContentsOfCSVFile:[lunchFileURL path] usedEncoding:&encoding error:nil];
[p setParserDelegate:self];
[p parse];
[p release];
Thanks for any help that someone can give me.
-[NSURL path] is not doing what you're expecting.
If I have the URL http://stackoverflow.com/questions/4636428, then it's -path is /questions/4636428. When you pass that path to CHCSVParser, it's going to try and open that path on the local system. Since that file doesn't exist, you won't be able to open it.
What you need to do (as Walter points out) is download the CSV file locally, and then open it. You can download the file in several different ways (+[NSString stringWithContentsOfURL:...], NSURLConnection, etc). Once you've got either the file saved locally to disk or the string of CSV in memory, you can then pass it to the parser.
If this is a very big file, then you'll want to alloc/init a CHCSVParser with the path to the local copy of the CSV file. The parser will then read through it bit by bit and tell you what it finds via the delegate callbacks.
If the CSV file isn't very big, then you can do:
NSString * csv = ...; //the NSString containing the contents of the CSV file
NSArray * rows = [csv CSVComponents];
That will return an NSArray of NSArrays of NSStrings.
Similar to this last approach is using the NSArray category method:
NSString * csv = ...;
NSError * error = nil;
NSArray * rows = [NSArray arrayWithContentsOfCSVString:csv encoding:[csv fastestEncoding] error:&error];
This will return the same structure (an NSArray of NSArrays of NSStrings), but it will also provide you with an NSError object if it encounters a syntax error in the CSV file (ie, malformed CSV).
I think you need an NSString, not an NSURL object to pass to the parser so the extra part you are doing with changing the NSString to an NSURL is the issue. Looking at the CHCSVParser documentation, it looks like he wants NSString in the init.
So maybe you could do something like:
NSError *err = [[[NSError alloc] init] autorelease];
NSString *lunchFileURL = [[NSString stringWithFormat:#"http://www.somewhere.com/LunchSpecials.csv"] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSString *lunchFile = [NSString stringWithContentsOfURL:[NSURL URLWithString:lunchFileURL] encoding:NSUTF8StringEncoding error:&err];
CHCSVParser *p = [[CHCSVParser alloc] initWithContentsOfCSVString:lunchFile usedEncoding:&encoding error:nil];

Troubles with NSString writeToFile

I am using the following code to open a file's contents and save it to another file.
when it runs the original file length is 793 but the saved file is 0. I have also tried just to copy the file. Nothing seems to work.
Is there some kind of permissions I'm missing on the documents directory?
NSError *error;
NSString *basePath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString* nGram = [basePath stringByAppendingPathComponent:#"contacts.gram"];
NSString *oGram = [basePath stringByAppendingPathComponent:#"/../vText.app/model/lm/TAR9230/contacts.gram"];
NSString *gramString = [[NSString alloc] initWithContentsOfFile:oGram encoding:NSUTF8StringEncoding error:&error];
BOOL ok = [gramString writeToFile:nGram atomically:NO encoding:NSUnicodeStringEncoding error:&error];
if(!ok) NSLog(#"Mayday!");
NSLog(#"%d",[gramString length]);
gramString = [[NSString alloc] initWithContentsOfFile:nGram encoding:NSUTF8StringEncoding error:&error];
NSLog(#"%d",[gramString length]);
This entire block is unnecessary. All you need is:
NSString *fp=[[NSBundle mainBundle] pathForResource:#"contacts" ofType:#"gram"];
NSString *gramString = [[NSString alloc] initWithContentsOfFile:fp
encoding:NSUTF8StringEncoding
error:&error];
You certainly don't want to try to directly access a file in the app bundle using a hardcoded path because the file isn't guaranteed to be in the same exact place in every build.
In the code you do have, you want to use the same encoding constant for reading as you did for writing. You write with NSUnicodeStringEncoding but you read with NSUTF8StringEncoding. These should overlap but why take the chance if you know the exact coding used?

iPhone Persistent Storage

I need to store certain information while my application is executing and again fetch it at the time the application starts. I tried storing it in XML using GData but didn't succeed.
I used the NSFileHandle it doesn't give me an error but it fails to create a .txt file for read / write purpose. Is there any other way of storing and retrieving the data on the iPhone. Below is my code for NSFileHandle.
NSString *path = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"myFile.txt"];
//NSFileHandle *fh = [NSFileHandle fileHandleForWritingAtPath:#"file://localhost/Users/shraddha/Desktop/info.txt"];
NSFileHandle *fh = [NSFileHandle fileHandleForWritingAtPath:#"myFile.txt"];
[fh seekToEndOfFile];
NSData *data = [camName dataUsingEncoding:NSASCIIStringEncoding];
[fh writeData:data];
[fh closeFile];
For Reading
NSString *path = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"myFile.txt"];
//NSFileHandle *fh = [NSFileHandle fileHandleForReadingAtPath:#"file://localhost/Users/shraddha/Desktop/info.txt"];
NSFileHandle *fh = [NSFileHandle fileHandleForReadingAtPath:#"myFile.txt"];
if(fh == nil)
return nil;
else
{
NSData *data = [fh readDataOfLength:8];
NSString *retStr = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];
return retStr;
}
You're trying to write to the resource directory which you probably don't have permission to do. Try changing the first line of your code to point to the document directory:
NSArray *savePaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSMutableString *savePath = [NSMutableString stringWithString:[savePaths objectAtIndex:0]];
[savePath appendString:#"/myFile.txt"];
Also, you don't need to worry about file handles. NSData is capable of writing itself to disk:
BOOL result = [data writeToFile:savePath atomically:YES];
You can use a sqlite database to store persistent data on the iPhone. Here is a blog post that should get you pointed in the right direction:
http://dblog.com.au/iphone-development-tutorials/iphone-sdk-tutorial-reading-data-from-a-sqlite-database/
Every iPhone application has at its disposal the ability to read/write name/value pairs which can be very, very useful for storing small information like user preferences. These preferences can also be edited by the user of your application (if you choose).
Another option you have which is more robust than trying to do text file storage and retrieval (I never liked this option, especially with the crappy XML parsing support on the iPhone) is sqlite. sqlite is a really light-weight relational database engine that is included with every iPhone and iPod touch.