Using writeToFile:atomically: consecutively doesn't work...why? - iphone

I'm trying to write a csv file. I have two arrays at hand - one with the titles (Name, Number etc), another with the actual values (Jon, 123 ...).
Now, after the following two operations:
[[titles componentsJoinedByString:#", "] writeToFile:file atomically:YES];
[[values componentsJoinedByString:#", "] writeToFile:file atomically:YES];
only the values array is written to the file. I realise that I may need to open the file again, but how do I do that after writing the first array? Or what is it exactly that I'm doing wrong if this is not the case?
Thanks!

The second line is in fact overwriting the file you wrote in the first line. One simple way to get around this problem would be to simply append the second string to the first (likely with an '\n' in between since you're making a csv file) and writing that string to your file:
NSString *str1 = [[titles componentsJoinedByString:#", "];
NSString *str2 = [[values componentsJoinedByString:#", "];
NSString *outputStr = [str1 stringByAppendingFormat:#"\n%#", str2];
[outputStr writeToFile:file atomically:YES];

Second time it replaces the old contents. So you could read the old content, append the old content with the new content and save on file.
Write first row
[[titles componentsJoinedByString:#", "] writeToFile:file atomically:YES];
Where you need to add another row every time
NSString *previousContent = [[NSString alloc] initWithContentsOfFile:file usedEncoding:nil error:nil];
NSString *str2 = [[values componentsJoinedByString:#", "];
NSString *outputStr = [previousContent stringByAppendingFormat:#"\n%#", str2];
[outputStr writeToFile:file atomically:YES];

Related

Json Values on Screen Objective c

NSDictionary *allDatDictionary = [NSJSONSerialization JSONObjectWithData:webData options:0 error:nil];
NSDictionary *responseData = [allDatDictionary objectForKey:#"responseData"];
NSDictionary *arrayOfResult = [responseData objectForKey:#"results"];
for (NSDictionary *diction in arrayOfResult) {
NSString *title = [diction objectForKey:#"title"];
NSString *content = [diction objectForKey:#"content"];
NSString *url = [diction objectForKey:#"url"];
[array addObject:title];
[content1 addObject:content];
[url1 addObject:url];
NSLog(#"title: %#, \n Content: %# \n, Url: %# \n", [diction objectForKey:#"title"], [diction objectForKey:#"content"],[diction objectForKey:#"url"]);
NSString *text = #"";
text = [NSString stringWithFormat:#"Title: %#%#\nURL: %#\nContent: %#\n\n", text, [diction objectForKey:#"title"],[diction objectForKey:#"url"],[diction objectForKey:#"content"]];
Hey guys, I got the json and I need to show title, content and url on screen. I don't need table ranting like this just show on screen. NSLog shows everything but when I try to write on a UILabel it just shows 1 result. Any tips how I can do that? thanks
You're setting labelTitle's text in a for loop, so you're only going to see the last result, because you keep changing it each time thru the loop. If you want to see all of the results, you'll have to build up a string that contains all of them and then set that as the text of the label.
At the top of the for loop, declare an NSString variable and set it to #"", like the following:
NSString *text = #"";
Then each time thru the loop, instead of setting the label text to your string, build up this string that you're saving at the top, like the following:
text = [NSString stringWithFormat:#"%#%#\n", text, [diction objectForKey:#"title"]];
You can see how I modified that format string. It takes the previous text you've saved, adds to it your new title, and then adds a carriage return.
As an alternative, you could have an NSMutableArray at the top, and add your strings to that array each time you go thru the for loop. Then at the end, you can use the NSArray method componentsJoinedByString:, using a carriage return as the separator, to get an NSString containing all of the individual strings that you added to the array.
After you have this one string, using either of these methods, you can set that as the text on the label.

Delete a line of text in txt file iOS

Is it possible to delete a line of text that store in .txt file. I am currently successful to extract each line inside txt file and add into array then display each line in TableView. Now I if I want to delete particular line How do I do it?
Put the strings from your NSArray into a NSMutableArray, delete the line that you want deleted, convert to a single NSString by joining elements with #"\n" string, and then write the string to file, like this:
NSMutableArray *tmp = [myArray mutableCopy];
[tmp removeObjectAtIndex:indexToRemove];
NSString *tmpStr = [NSString componentsJoinedByString:#"\n"];
NSError *err = nil;
[tmpStr writeToFile:myFile
atomically:NO
encoding:NSUTF8StringEncoding // <== use an encoding that you need
error:&err];

Add text to existing txt file [duplicate]

This question already has answers here:
write data line by line on iphone
(4 answers)
Closed 9 years ago.
How can I add text from UITextField, separated by comma to existing txt file?
I use this code:
NSString *imageName = [NSString stringWithFormat:#"Documents/text.txt"];
NSString *textPath = [NSHomeDirectory() stringByAppendingPathComponent:imageName];
NSString *word = [NSString stringWithFormat:#"%# ,", _wordInput.text];
[word writeToFile:textPath atomically:YES encoding:NSUTF8StringEncoding error:nil];
As you can see, I use this code to add a text from _wordInput which is my UITextField, and add comma. After that I use writeToFile option to write text to my text.txt file.
I tested, and works great, but, every time it will overwrite existing text..
Help please to NOT OVERWRITE TEXT, BUT separate by comma.
Let's say my UITextField has text "earth" at this moment, I will press a button, and the above code will run.. Now my text.txt file will contain "earth ," if I will enter another text on UITextField and run above code, the existing text will be overwrite, but I need it to be added after "earth ,"
Thanks.
It is better to use something like below function:
-(void)saveText:(NSString*)data
{
NSString *imageName = [NSString stringWithFormat:#"Documents/text.txt"];
NSString *textPath = [NSHomeDirectory() stringByAppendingPathComponent:imageName];
NSString *word = [NSString stringWithFormat:#"%# ,", _wordInput.text];
NSFileHandle *fileHandler= [NSFileHandle fileHandleForWritingAtPath:textPath];
[fileHandler seekToEndOfFile];
[fileHandler writeData:[word dataUsingEncoding:NSUTF8StringEncoding]];
[fileHandler closeFile];
}
You need to include the original text when you write it back. Something like this:
NSString *imageName = [NSString stringWithFormat:#"Documents/text.txt"];
NSString *textPath = [NSHomeDirectory() stringByAppendingPathComponent:imageName];
NSString *existingFileContents = [NSString stringWithContentsOfFile:textPath encoding:NSUTF8StringEncoding error:nil];
NSString *newFileContents = [NSString stringWithFormat:#"%#, %#", existingFileContents, _wordInput.text];
[newFileContents writeToFile:textPath atomically:YES encoding:NSUTF8StringEncoding error:nil];
I would assume that using system api calls like write() or fwrite() would be more efficient, but I've never measured it. If your text file is large, you might want to look into it.

parsing text file in objective C

i am trying to parse a text file saved in doc dir below show is the code for it
NSArray *filePaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES);
NSString *docDirPath=[filePaths objectAtIndex:0];
NSString *filePath=[docDirPath stringByAppendingPathComponent:#"SKU.txt"];
NSError *error;
NSString *fileContents=[NSString stringWithContentsOfFile:filePath];
NSLog(#"fileContents---%#",fileContents);
if(!fileContents)
NSLog(#"error in reading file----%#",error);
NSArray *values=[fileContents componentsSeparatedByString:#"\n"];
NSLog(#"values-----%#",values);
NSMutableArray *parsedValues=[[NSMutableArray alloc]init];
for(int i=0;i<[values count];i++){
NSString *lineStr=[values objectAtIndex:i];
NSLog(#"linestr---%#",lineStr);
NSMutableDictionary *valuesDic=[[NSMutableDictionary alloc]init];
NSArray *seperatedValues=[[NSArray alloc]init];
seperatedValues=[lineStr componentsSeparatedByString:#","];
NSLog(#"seperatedvalues---%#",seperatedValues);
[valuesDic setObject:seperatedValues forKey:[seperatedValues objectAtIndex:0]];
NSLog(#"valuesDic---%#",valuesDic);
[parsedValues addObject:valuesDic];
[seperatedValues release];
[valuesDic release];
}
NSLog(#"parsedValues----%#",parsedValues);
NSMutableDictionary *result;
result=[parsedValues objectAtIndex:1];
NSLog(#"res----%#",[result objectForKey:#"WALM-FT"]);
The problem what i am facing is when i try to print lineStr ie the data of the text file it is printing as a single string so i could not able to get the contents in line by line way please help me solve this issue.
Instead use:
- (NSArray *)componentsSeparatedByCharactersInSet:(NSCharacterSet *)separator
it covers several different newline characters.
Example:
NSArray *values = [fileContents componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]];
for (NSString *lineStr in values) {
// Parsing code here
}
ALso seperatedValues is over released. First one is created with alloc init, then on the next line it is replaced by the method componentsSeparatedByString. So the first one od lost without being released, that is a leak. Later the seperatedValues created by componentsSeparatedByString is released but it is already auto released by componentsSeparatedByString to that is an over release;
Solve all the retain/release/autorelease problem with ARC (Automatic Reference Counting).
Here is a version that uses convenience methods and omits over release:
NSArray *values = [fileContents componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]];
for (NSString *lineStr in values) {
NSArray *seperatedValues = [lineStr componentsSeparatedByString:#","];
NSString *key = [seperatedValues objectAtIndex:0];
NSDictionary *valuesDic = [NSDictionary dictionaryWithObject:seperatedValues forKey:key];
[parsedValues addObject:valuesDic];
}
NSLog(#"parsedValues---%#",parsedValues);
Are you sure the line separator used in your text file is \n and not \r (or \r\n)?
The problem may come from this, explaining why you don't manage to split the files into different lines.

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];