I'm trying to retrieve content of a csv file to NSString. Thats what I do:
NSString *strBundle = [[NSBundle mainBundle] pathForResource:#"socs" ofType:#"csv"];
NSLog(#"bundle path: %#",strBundle);
NSString *file = [NSString stringWithContentsOfFile:strBundle
encoding:NSUTF8StringEncoding
error:nil];
if ([[NSFileManager defaultManager]fileExistsAtPath:strBundle]) {
NSLog(#"file is there!!!");
}else {
NSLog(#"no file");
}
NSLog(#"file: %#",file);
NSArray *allLines = [file componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]];
NSLog(#"lines: %lu",(unsigned long)[allLines count]);
file manager shows that the file is there. When i try to log the NSString or number of files it says null. I even created NSData object with the content of exactly the same file and when I logged the NSData object, I clearly saw that there is some data. Then when I tried to create NSString with the content of NSData, I had the same result as before - null. Maybe the problem is somewhere in the formatting of the file?
Any help will be appreciated :)
I see 3 issues:
You are passing a nil argument to the error: parameter in your stringWithContentsOfFile: line. If there's a possibility something might go wrong (and apparently there is), you should pass a real argument there so you can figure out what went wrong.
You can use componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet], but that has a tendency to produce blank "components" between every line. Plain old #"\n" works better in virtually all cases I've run into.
You should be checking fileExistsAtPath before you try to load it into the NSString
If you were truly able to create an NSData object from the path it doesn't necessarily mean it's correct data. But let's say it is, if you were not able to convert it to a NSString then you need to check your encoding parameter.
Related
I have a .txt file in which some data is present, when I stored it in an array I got 50000 words. I want to search the data from text file according to user input and show it on UITableview cell, how is it possible ?
Can any body help me?
Here is my code to read data from .txt file in viewDidLoad:
NSString *filepath = [[NSBundle mainBundle] pathForResource:#"myList" ofType:#"txt"];
NSError *error;
NSString *fileContents = [NSString stringWithContentsOfFile:filepath encoding:NSUTF8StringEncoding error:&error];
if (error)
NSLog(#"Error reading file: %#", error.localizedDescription);
// maybe for debugging...
NSLog(#"contents: %#", fileContents);
NSArray *listArray = [fileContents componentsSeparatedByString:#"\n"];
NSLog(#"items = %d", [listArray count]);
You should use fast enumeration using block. Those are fastest of all for loop iteration. But changing the value in that array at time of enumeration could cause a crash.
Here is a link of how to use block enumeration
Here is a link of how it performance wise.
Hope this helps you!!
This question already has an answer here:
Writing a NSArray to file
(1 answer)
Closed 9 years ago.
I have an app which has several ViewControllers. Each ViewController has a question with 2-5 buttons as possible answers. The title of a button is saved to a NSMutableArray called submission. The user can go back to previous questions, change their answer, and the NSMutableArray will be updated accordingly. I need to save this array to file so new results can be saved into a UITableView each time the questionnaire is completed. I have researched and it sounds like a .plist is a good option, as all of my objects in the array are NSStrings.
A sample of my array:
2013-12-17 14:06:34.210 Questionnaire[1724:70b] (
1234,
"Dec 17, 2013",
Yes,
Games,
"Not Applicable",
Yes
)
"1234" is the User ID, the date is the Date of Birth, and the other submissions are the answers to each question.
My ViewControllers look like this:
MainViewController
InfoViewController <-- Array allocated + initialised, inserting ID and DoB
Q1ViewController <-- question
..
Q4ViewController <--question
ENDViewController <-- offers user options for Home or Results
ResultsViewController <-- UITableView ordered by User ID
SavedResultsViewController <-- UITableView showing complete submission
The NSMutableArray gets passed through each ViewController.
My questions: What method of saving to file would best suit my needs? (.plist, filetype, etc). Viewing the results on Excel would be nice (but not essential). Where should the save take place? I was thinking when the last object is inserted into the array on Q4 ViewController, so it would be saved to file when the ENDViewController is popped, is this logical? Do I need to create a new Objective-C file to store the data? I have saw a few tutorials explaining this, declaring each object in a separate NSObject file, although I'm not sure if that is needed as my objects are already stored in the array.
As you've probably guessed I am quite new to Objective-C and iOS programming, so any help offered is greatly appreciated. I am not sure how else to describe my problem, so apologies if the question is still unclear.
Edit: I have learnt a bit more about Objective-C since creating this post, and have decided to save my data to a .csv file. This file is strictly for the purpose of emailing, it doesn't get displayed on the UITableView (I am currently implementing Core Data for that). This solution might help someone in the future, so here it is:
// Set column titles for .csv
NSArray *columnTitleArray = #[#"User ID", #"DoB", #"Question 1", #"Question 2", #"Question 3", #"Question 4"];
NSString *columnTitle = [columnTitleArray componentsJoinedByString:#","];
NSString *columnTitleToWrite = [columnTitle stringByAppendingString:#"\n"];
// Separate submissions from array into cells
NSString *questionResults = [self.submission componentsJoinedByString:#","];
NSString *questionResultsToWrite = [questionResults stringByAppendingString:#"\n"];
// Find documents directory
NSString *docPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
// Set file name and type
NSString *survey = [docPath stringByAppendingPathComponent:#"result.csv"];
// Create new file if none exists
if (![[NSFileManager defaultManager] fileExistsAtPath:survey]){
[[NSFileManager defaultManager] createFileAtPath:survey contents:nil attributes:nil];
// Set column titles for new file
NSFileHandle *fileHandle = [NSFileHandle fileHandleForUpdatingAtPath:survey];
[fileHandle writeData:[columnTitleToWrite dataUsingEncoding:NSUTF8StringEncoding]];
}
NSFileHandle *fileHandle = [NSFileHandle fileHandleForUpdatingAtPath:survey];
[fileHandle seekToEndOfFile];
[fileHandle writeData:[questionResultsToWrite dataUsingEncoding:NSUTF8StringEncoding]];
[fileHandle closeFile];
You could save your array as a JSON file. This would allow you to view it in a text editor, but not a spreadsheet. The following code will write it out as JSON to a file:
NSURL *url = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
url = [url URLByAppendingPathComponent:#"yourdata.json"];
NSError *e = nil;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:yourdata options:NSJSONWritingPrettyPrinted error:&e];
if (jsonData) {
[jsonData writeToFile:url.path atomically:YES];
}
You could also save your data as a plist file. The following will write the data to a plist:
NSURL *url = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
url = [url URLByAppendingPathComponent:#"yourdata.plist"];
NSError *e = nil;
NSData *plistData = [NSPropertyListSerialization dataWithPropertyList:yourdata format:NSPropertyListXMLFormat_v1_0 options:0 error:&e];
if (plistData) {
[plistData writeToFile:url.path atomically:YES];
}
Plists can be saved in binary or XML format, and the above will save it as XML format, which means the XML will also be readable with a text editor. Again, this won't be viewable as a spreadsheet. If you want to export your data in CSV format, you'll probably have to write your own code to output it.
You can use standard NSCoding protocol for saving data but in this case you can't read it in excel.
Or you can save it in xml.
Or you can manually create a csv (comma separated values) file and open it anywhere.
Implementation is up to you anyway :)
I've looked around a bit and tried a few things, but none have really worked. What I'm trying to do is create a NSArray of NSStrings, with each array value corresponding to one line from the Rich Text File I'm referencing. At first I tried this:
NSArray* data = [[NSString stringWithContentsOfFile:#"relevantFile.rtf" encoding:4 error:nil] componentsSeparatedByCharactersInSet: [NSCharacterSet newlineCharacterSet]];
I've also tried this, because I found it in the iOS developer library:
NSArray* data = [[NSArray alloc] initWithContentsOfFile:#"relevantFile.rtf"];
However, neither of these has worked for me. A few lines later in the code, in order to diagnose errors, I have the following code:
for(int i = 0; i < [data count]; i++)
{
NSLog(#"%#", [data objectAtIndex: i]);
}
...for which NSLog is printing "(null)". I'm not entirely sure what I'm doing wrong here -- should I be using mutable strings or arrays, or is there some better way to go about this that I don't know about?
That first line you posted should do it. My guess would be that it's not finding the file. Not specifying an absolute path, the app will look in the current directory which is probably NOT where the file is.
If the file is a resource that is compiled into your app bundle, you can use the following code to obtain the path to it:
NSString* path = [[NSBundle mainBundle] pathForResource: #"relevantFile" ofType: #"rtf"]
NSArray* data = [[NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil] componentsSeparatedByCharactersInSet: [NSCharacterSet newlineCharacterSet]];
Getting a warning saying that:
Collection expression type 'NSString *' may not respond to 'countByEnumeratingWithState:objects:count'
when trying to run the following code:
NSString *proper = [NSString stringWithContentsOfFile:#"usr/share/dict/propernames" encoding:NSUTF8StringEncoding error:NULL];
for (NSString *i in proper){
NSLog(#"Item>%#", i);
}
When I run the program I don't get any output from the NSLog statement. Anyone run into this?
The compiler warning is trying to tell you that you cannot iterate over an NSString using a for ... in ... loop. It is further trying to say than the reason for this is that an NSString is not a valid "Collection" type. Your valid "Collection" types are things like NSArray, NSSet, and NSDictionary.
So if your file is supposed to contain structured data, you should parse it into something more useful than a flat NSString. Something like this may give a better result:
NSString* temp = [NSString stringWithContentsOfFile:#"usr/share/dict/propernames" encoding:NSUTF8StringEncoding error:NULL];
NSArray* proper = [temp componentsSeparatedByString:#"\n"];
for (NSString* i in proper){
NSLog(#"Item>%#", i);
}
That will print each line in the file. This assumes, of course, that your input file has one entry per line. If it is structured some other way, then you will have to parse it differently.
After you load the file, split it into lines with componentsSeparatedByString: .
NSArray *lines = [proper componentsSeparatedByString:#"\n"]; // Use the correct line ending character here
for (NSString *i in lines) {
NSLog(#"item> %#", i);
}
This is a clear mistake u have here.
NSString* is a string object and is not a collection of characters as the string object known in C++ which is a character array.
for-in Loop need a collection to iterate within. like NSArray or NSSet.
I create a NSArray and write to a file: a.plist.
I use NSString: initWithContentsOfFile, and I can see the content in xml.
Then, I add a.plist to another project
and then I use NSString: initWithContentsOfFile to get the xml string.
filePath = [[NSBundle mainBundle] pathForResource:#"a" ofType:#"plist"];
NSString *plistStr = [[NSString alloc]initWithContentsOfFile:filePath];
However, it failed to recreate the xml string.
I user NSArray to test:
NSArray *plist2Array = [[NSArray alloc]initWithContentsOfFile:filePath];
But it successfully.
I think it may result from "Text Encoding" when I add it to another project.
The problem is I tried UTF8,UTF16 and so on.
I still can't find solution.
Hope for your help,thanks!
I find it!
rename the file: a.plist ->a.txt(or any else),
then in another project you can get the xml string.