// // BBCVSExporter.m // // Created by Matt on 12/3/09. #import "BBCSVExporter.h" @implementation BBCSVExporter +(id)exporter { return [[[BBCSVExporter alloc] init] autorelease]; } -(void)exportArrayAsCSV:(NSArray*)data toFile:(NSString*)filePath { //data in this case should be an NSArray, each item of which is another NSArray, which contains //the field data //every single subarray should have exactly the same number of items (number of columns) //each item of the parent 'data' array is a row //This method is a bit bulky and simply provides a 'shortcut', //anyone processing huge amounts of data may want to refine for more efficient memory use NSMutableArray *a = [NSMutableArray array]; NSEnumerator *e = [data objectEnumerator]; int colCount = [[data objectAtIndex: 0] count]; NSArray *a2; while((a2 = [e nextObject])) { [a addObjectsFromArray: a2]; } [self exportArrayAsCSV: a numberOfColumns: colCount toFile: filePath]; } -(void)exportArrayAsCSV:(NSArray*)data numberOfColumns:(int)cols toFile:(NSString*)filePath { if(cols <= 0) return; if(!data) return; if(![data count]) return; if(!filePath) return; if(![filePath length]) return; NSEnumerator *e = [data objectEnumerator]; id obj; NSMutableString *str = [NSMutableString string]; int c = 0; NSMutableString *d; Class numberClass = [NSNumber class]; NSMutableString *emptyStr = [NSMutableString stringWithString: @""]; NSUInteger rep1, rep2, rep3; //****** //Note: handling here is not terribly efficient, but it is designed for simplicity //and code readability. Users exporting large amounts of data may want to refine this //for smarter memory/CPU usage //****** while((obj = [e nextObject])) { if([[obj class] isKindOfClass: numberClass]) { //grab the string value and skip over any comma/quotation/NL checks d = [NSMutableString stringWithString: [obj stringValue]]; } else if(obj == [NSNull null]) { d = emptyStr; } else { //grab the object's human-readable form: d = [NSMutableString stringWithString: [obj description]]; //adjust for commas and quotes if needed rep1 = rep2 = rep3 = 0; rep1 = [d replaceOccurrencesOfString: @"\"" withString:@"\"\"" options: 0 range: NSMakeRange(0,[d length])]; if(!rep1) //do we need to enclose? { //check for commas rep2 = [d rangeOfString: @","].length; if(!rep2) { //check for newlines rep3 = [d rangeOfString: @"\n"].length; } } if(rep1 || rep2 || rep3) { //enclose string in quotes [d setString: [NSString stringWithFormat: @"\"%@\"",d]]; } } [str appendString: d]; c++; if(c == cols) { //new row, go to a new line [str appendString: @"\n"]; c = 0; } else { //new field, add a coma [str appendString: @","]; } } //done creating string data, now output file: NSError *err = nil; NSString *finalPath; //lets make sure we have the proper file extension here: if(![[[filePath pathExtension] lowercaseString] isEqualToString: @"csv"]) { finalPath = [filePath stringByDeletingPathExtension]; finalPath = [finalPath stringByAppendingPathExtension: @"csv"]; } else { //OK finalPath = filePath; } [str writeToFile: finalPath atomically: YES encoding: NSUTF8StringEncoding error: &err]; if(err) { NSLog(@"err"); } } @end