I have a .csv file in my bundle which I need to parse into an NSArray. The problem is when I init an NSString with contents of file (the file is located in my bundle), it returns nil. However, if I change the contents of the file, to anything else (random), it works. Is it possible there's some sort of string/character in the file that might be messing with the initialization?
It's just a simple csv file with 2 columns, a number, a comma, some text and "\n".
Thanks.
CSV => NSArray?
https://github.com/davedelong/CHCSVParser
*disclaimer: I wrote it.
Works for me:
NSStringEncoding usedEncoding = 0;
NSError *csvError = nil;
NSString *raw = [NSString stringWithContentsOfURL:[NSURL URLWithString:#"http://pastebin.com/raw.php?i=RXPPwpvy"] usedEncoding:&usedEncoding error:&csvError];
NSLog(#"raw: %#", raw);
NSLog(#"%#", [NSArray arrayWithContentsOfCSVString:raw encoding:usedEncoding error:&csvError]);
Related
My program loads some data from a file and then draws them.
The file-reading part is like this:
- (void)load_file
{
NSFileHandle *inFile = [NSFileHandle fileHandleForReadingAtPath:#"map_data"];
NSData *myData=[inFile readDataToEndOfFile];
NSString *myText=[[NSString alloc]initWithData:myData encoding:NSASCIIStringEncoding];
NSArray *values = [myText componentsSeparatedByString:#"\n"];
for (NSString *string in values) {
NSArray *lines=[string componentsSeparatedByString:#" "];
if ([lines count] != 2) break;
NSPoint point= NSMakePoint([lines[0] floatValue], [lines[1] floatValue]);
[points addObject:[NSValue valueWithPoint:point]];
}
[self setNeedsDisplay:YES];
}
When debugging, I put the data file in the directory of [NSBundle mainBundle], and the program works fine.
However, when I use achieve to take the app out, it never runs. I put the data file in the same path with the app, but it seems fail to load it.
Update
I tried to use c++, but still fails.
- (void)load_file
{
ifstream inf("map_data");
double x, y;
while (inf >> x >> y) [points addObject:[NSValue valueWithPoint:NSMakePoint(x, y)]];
inf.close();
}
I tried to change the build scheme to release and run, which is fine. But whenever I go directly into the finder of app and double click it, it does not work and seems nothing is loaded.
add the file to the project as a Resource (this will cause it to be copied into the app wrapper in the right spot)
use `[[NSBundle mainBundle] pathForResource:#"map_data" ofType:nil];
That should give you the path to the file. The file should not be manually copied, it should not be next to the app wrapper, nor should you [conjecture] ever try changing or replacing the file once it is in your app wrapper.
The reason why it seems to work sometimes is mere coincidence. You are passing a partial path to NSFileHandle and it happens that the current working directory of your app sometimes points to the right spot such that the data file is available.
I'm not sure how relative paths are handled by NSFileHandle, but usually you set up paths using the NSBundle class.
NSString *path = [[NSBundle mainBundle] pathForResource:#"myfile" ofType:#"ext"];
You can also simply initialize an NSString from the contents of a file, you don't need to first read it into an NSData using NSFileHandle.
NSString *text = [[NSString alloc] initWithContentsOfFile:path
encoding:NSASCIIStringEncoding error:nil];
(Use the error parameter, if you want proper error handling)
After much reading it seems that, really, the only way to read a number of lines from a text file into an NSArray is with this:
NSString *myfilePath = [[NSBundle mainBundle] pathForResource:#"poem" ofType:#"txt"];
NSString *linesFromFile = [[NSString alloc] initWithContentsOfFile:myfilePath encoding:NSUTF8StringEncoding error:nil];
myArrayOfLines = [NSArray alloc];
myArrayOfLines = [linesFromFile componentsSeparatedByString:#"\n"];
NSArrays have a method for initWithContentsOfFile but I have not seen any examples of how to use this. I have read some posts that state that the file must be a plist and not a generic txt file.
Is this really the case? Is there a way to read lines (terminated with \n) directly into an NSArray?
You have it right, except the line myArrayOfLines = [NSArray alloc]; which is useless.
Don't bother with plist if you already have a good txt file.
But for curiosity, here is a link which explains how it works with plist files : link
Also, if you don't use ARC, you'll have some leaks, but that's another question, and we don't have the whole code, so I might be wrong.
How can I read and write an integer to and from a text file, and is it possible to read or write to multiple lines, i.e., deal with multiple integers?
Thanks.
This is certainly possible; it simply depends on the exact format of the text file.
Reading the contents of a text file is easy:
// If you want to handle an error, don't pass NULL to the following code, but rather an NSError pointer.
NSString *contents = [NSString stringWithContentsOfFile:#"/path/to/file" encoding:NSUTF8StringEncoding error:NULL];
That creates an autoreleased string containing the entire file. If all the file contains is an integer, you can just write this:
NSInteger integer = [contents integerValue];
If the file is split up into multiple lines (with each line containing one integer), you'll have to split it up:
NSArray *lines = [contents componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]];
for (NSString *line in lines) {
NSInteger currentInteger = [line integerValue];
// Do something with the integer.
}
Overall, it's very simple.
Writing back to a file is just as easy. Once you've manipulated what you wanted back into a string, you can just use this:
NSString *newContents = ...; // New string.
[newContents writeToFile:#"/path/to/file" atomically:YES encoding:NSUTF8StringEncoding error:NULL];
You can use that to write to a string. Of course, you can play with the settings. Setting atomically to YES causes it to write to a test file first, verify it, and then copy it over to replace the old file (this ensures that if some failure happens, you won't end up with a corrupt file). If you want, you can use a different encoding (though NSUTF8StringEncoding is highly recommended), and if you want to catch errors (which you should, essentially), you can pass in a reference to an NSError to the method. It would look something like this:
NSError *error = nil;
[newContents writeToFile:#"someFile.txt" atomically:YES encoding:NSUTF8StringEncoding error:&error];
if (error) {
// Some error has occurred. Handle it.
}
For further reading, consult the NSString Class Reference.
If you have to write to multiple lines, use \r\n when building the newContents string to specify where line breaks are to be placed.
NSMutableString *newContents = [[NSMutableString alloc] init];
for (/* loop conditions here */)
{
NSString *lineString = //...do stuff to put important info for this line...
[newContents appendString:lineString];
[newContents appendString:#"\r\n"];
}
In my app I have to read an XML file and display it in a UITextView. To do this I tried the code below. This code is resulting in a crash; can any one tell me the exact mistake? I hope I wrote well. Please help me out. Thank you.
-(IBAction)xmlParse{
NSString *xmlPath=[[[[UIApplication sharedApplication]delegate] applicationDocumentDirectory]stringByAppendingPathComponent:#"xmlFile/toc.xml"];
NSError *error=nil;
NSString *fileContent=[NSString stringWithContentsOfFile:xmlPath usedEncoding:NSASCIIStringEncoding error:NULL];
xmlDisplay.text=fileContent;
}
replace
NSString *fileContent=[NSString stringWithContentsOfFile:xmlPath usedEncoding:NSASCIIStringEncoding error:NULL];
with
NSString *fileContent=[NSString stringWithContentsOfFile:xmlPath encoding:NSASCIIStringEncoding error:NULL];
you should not ignore the assing argument 2 of 'stringWithContentsOfFile:usedEncoding:error:' makes pointer from integer without a cast warning the compiler shows you.
i was facing same issue earlier . it is batter to save xml file inside document Directory itself not in any sub Folder .try to save in to Document Directory . hope should work....
or u can try
-(IBAction)xmlParse{
NSString *xmlPath=[[[[UIApplication sharedApplication]delegate] applicationDocumentDirectory]stringByAppendingPathComponent:#"xmlFile/toc.xml"];
NSError *error=nil;
NSString *fileContent=[NSString stringWithContentsOfFile:xmlPath usedEncoding:NSASCIIStringEncoding error:NULL];
if(nil!=fileContent)
xmlDisplay.text=fileContent;
I'm using a text file to save the changes made by a user on a list (the reason that I'm doing this is so that I can upload the text file to a PC later on, and from there insert it into an Excel spreadsheet). I have 3 data structures: A NSMutableArray of keys, and a NSMutableDictionary who's key values are MSMutableArrays of NSStrings.
I iterate through these data structures and compile a file string that looks much like this:
(Key);(value)\t(value)\t(value):\n(Key);(value).. .so on.
SO, onto the actual question: When I attempt to save it, it fails. I'm 99% sure this is because of the file path that I'm using, but I wanted backup to check this out. Code follows:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask, YES);
NSString *filePath = [paths objectAtIndex:0];
NSString *fileString = [NSString stringWithString:[self toFileString]];
if(![fileString writeToFile:filePath atomically:YES encoding:NSUTF8StringEncoding error:NULL]){
NSLog(#"File save failed");
} else {
// do stuff
}
(Code above is re-copied, since the actual code is on a different computer. It compiles, so ignore spelling errors?)
I tried using NSError, but I got bogged down in documentation and figured I might as well ask SO while trying to figure out how to properly use NSError (might be a little bit of an idiot, sorry).
99% sure it's the NSArray *paths line that's tripping it up, but I don't know how else to get the documents directory.
Edit: Problem solved, and one final question: If I save it to the App's document directory, where can I go after I close the app to see if it saved properly? If it works like I think it does, isn't it sandboxed in with the app's installation on the simulator? (i.e. no way of checking it)
NSLog() that filePath string. I think you're trying to write to the directory itself, not to a file.
Try this instead:
filePath = [[paths objectAtIndex:0]stringByAppendingPathComponent:#"myfile.txt"];
What is the file name you want to save? The method
NSArray *paths = NSSearchPathForDirectoriesInDomains(...);
NSString *filePath = [paths objectAtIndex:0];
...
if(![fileString writeToFile:filePath ...
means you are saving the string into a file path which has the same name as a folder. This will of course fail. Please give it a name, e.g.
NSString* fileName = [filePath stringByAppendingPathComponent:#"file.txt"];
if(![fileString writeToFile:fileName ...
and try again.
BTW, to use NSError:
NSError* theError = nil;
if(![fileString writeToFile:fileName ... error:&theError]) {
// ^^^^^^^^^
NSLog(#"Failed with reason %#", theError);
// theError is autoreleased.
}