如何使用CHCSVParser类

时间:2010-09-24 14:56:38

标签: iphone objective-c core-data csv

我正在使用Dave DeLong的Objective-C优秀的CHCSVParser和一个非常长的.CSV文件,并且使用它时遇到了一些麻烦。我会使用arrayWithContentsOfCSVFile方法,但是我在iPhone上运行代码并将整个文件解析到内存中会占用更多内存。

在我的下面的代码中,解析器打开文档并完美地调用委托方法,但是在委托中的哪个位置我会在每行之后停止并访问数据(以创建Core Data对象并将其保存到数据存储中)?我假设它会在- (void) parser:(CHCSVParser *)parser didEndLine:(NSUInteger)lineNumber中,但是如果使用该行完成,我如何从解析器获得NSArray(或其他)数据?

到目前为止,这是我的代码:

//
// The code from a method in my view controller:
//
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSFileManager *manager = [NSFileManager defaultManager];
NSError *err = nil;
NSArray *fileList = [manager contentsOfDirectoryAtPath:documentsDirectory error:&err];
NSString *fileName = [fileList objectAtIndex:1];
NSURL *inputFileURL = [NSURL fileURLWithPath: [documentsDirectory stringByAppendingPathComponent:fileName]];


NSStringEncoding encoding = 0;
CHCSVParser *p = [[CHCSVParser alloc] initWithContentsOfCSVFile:[inputFileURL path] usedEncoding:&encoding error:nil];
[p setParserDelegate:self];
[p parse];
[p release];

...

#pragma mark -
#pragma mark CHCSVParserDelegate methods

- (void) parser:(CHCSVParser *)parser didStartDocument:(NSString *)csvFile {
    NSLog(@"Parser started!");
}

- (void) parser:(CHCSVParser *)parser didStartLine:(NSUInteger)lineNumber {
    //NSLog(@"Parser started line: %i", lineNumber);
}

- (void) parser:(CHCSVParser *)parser didEndLine:(NSUInteger)lineNumber {
    NSLog(@"Parser ended line: %i", lineNumber);
}

- (void) parser:(CHCSVParser *)parser didReadField:(NSString *)field {
    //NSLog(@"Parser didReadField: %@", field);
}

- (void) parser:(CHCSVParser *)parser didEndDocument:(NSString *)csvFile {
    NSLog(@"Parser ended document: %@", csvFile);
}

- (void) parser:(CHCSVParser *)parser didFailWithError:(NSError *)error {
    NSLog(@"Parser failed with error: %@ %@", [error localizedDescription], [error userInfo]);
}

谢谢!

3 个答案:

答案 0 :(得分:17)

我很高兴看到我的代码证明是有用的! :)

CHCSVParser在行为上类似于NSXMLParser,因为每次发现有趣的内容时,它都会通过其中一个委托回调告诉您。但是,如果您选择忽略它在回调中提供的数据,那么它就消失了。这些解析器(CHCSVParserNSXMLParser)非常愚蠢。他们只知道他们试图解析的东西的格式,但除此之外并没有那么多。

简而言之,答案是“你必须自己保存”。如果查看NSArray类别的代码,您将在.m文件中看到它正在使用a simple NSObject subclass as the parser delegate,该子类是将字段聚合到一个数组中,然后添加该数组整个阵列。你需要做类似的事情。

示例委托:

@interface CSVParserDelegate : NSObject <CHCSVParserDelegate> {
  NSMutableArray * currentRow;
}
@end

@implementation CSVParserDelegate

- (void) parser:(CHCSVParser *)parser didStartLine:(NSUInteger)lineNumber {
  currentRow = [[NSMutableArray alloc] init];
}
- (void) parser:(CHCSVParser *)parser didReadField:(NSString *)field {
  [currentRow addObject:field];
}
- (void) parser:(CHCSVParser *)parser didEndLine:(NSUInteger)lineNumber {
  NSLog(@"finished line! %@", currentRow);
  [self doSomethingWithLine:currentRow];
  [currentRow release], currentRow = nil;
}
@end

但是,我可以确信修改解析器的行为以聚合行本身,但是如果我沿着那条路走下去,为什么不让解析器聚合整个文件呢? (答案:不应该)

答案 1 :(得分:1)

我今天尝试使用这个,基于@ DaveDeLong的优秀答案和代码,但我认为自从他(2010)回答以来该软件已被修改。在撰写本文时,我发现我必须使用它:

@interface CSVParserDelegate : NSObject <CHCSVParserDelegate> {
  NSMutableArray * currentRow;
}
@end

@implementation CSVParserDelegate

- (void) parser:(CHCSVParser *)parser didBeginLine:(NSUInteger)lineNumber {
  currentRow = [[NSMutableArray alloc] init];
}
- (void) parser:(CHCSVParser *)parser didReadField:(NSString *)field atIndex:(NSInteger)fieldIndex {
  [currentRow addObject:field];
}
- (void) parser:(CHCSVParser *)parser didEndLine:(NSUInteger)lineNumber {
  NSLog(@"finished line! %@", currentRow);
  [self doSomethingWithLine:currentRow];
  [currentRow release], currentRow = nil;
}
@end

即,parser:didStartLine:lineNumber:已成为parser:didBeginLine:lineNumber:parser:didReadField:已成为parser:didReadField:atIndex:

答案 2 :(得分:0)

要将CHCSVParser与Swift结合使用,可以使用a swift wrapper满足基本需求