如何使用 CHCSVParser 类
我正在使用 Dave DeLong 的优秀 CHCSVParser for Objective-C 和一个非常长的 .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]);
}
谢谢!
I am playing around with Dave DeLong's excellent CHCSVParser for Objective-C with an extremely long .CSV file and am running into some trouble using it. I would use the arrayWithContentsOfCSVFile
method, but I'm running the code on an iPhone and parsing the whole file into memory would take more memory than is available.
In my code below, the parser opens the document and calls the delegate methods perfectly, but where in the delegate do I stop after each line and access the data (to create and save a Core Data object to the data store)? I assume that would be in - (void) parser:(CHCSVParser *)parser didEndLine:(NSUInteger)lineNumber
, but how do I get an NSArray
(or whatever) of the data from the parser when it's done with the line?
Here is my code so far:
//
// 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]);
}
Thanks!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我很高兴看到我的代码被证明是有用的! :)
CHCSVParser
的行为与NSXMLParser
类似,每次它发现一些有趣的东西时,它都会通过委托回调之一让您知道。但是,如果您选择忽略它在回调中为您提供的数据,那么它就会消失。这些解析器(CHCSVParser
和NSXMLParser
)非常愚蠢。他们只知道他们试图解析的内容的格式,但除此之外并没有真正做太多事情。简而言之,答案就是“你必须自己保存”。如果您查看
NSArray
类别的代码,您会在 .m 文件中看到它使用 一个简单的NSObject
子类作为解析器委托,该子类将字段聚合到数组中,然后添加该数组到整个数组。你需要做类似的事情。示例委托:
但是,我可以确信修改解析器的行为以聚合行本身,但如果我沿着这条路线走下去,为什么不让解析器聚合整个文件呢? (答案:不应该)
I'm glad to see that my code is proving useful! :)
CHCSVParser
is similar in behavior to anNSXMLParser
, in that every time it finds something interesting, it's going to let you know via one of the delegate callbacks. However, if you choose to ignore the data that it gives you in the callback, then it's gone. These parsers (CHCSVParser
andNSXMLParser
) are pretty stupid. They just know the format of the stuff they're trying to parse, but don't really do much beyond that.So the answer, in a nutshell, is "you have to save it yourself". If you look at the code for the
NSArray
category, you'll see in the .m file that it's using a simpleNSObject
subclass as the parser delegate, and that subclass is what's aggregating the fields into an array, and then adding that array to the overall array. You'll need to do something similar.Example delegate:
However, I could be convinced to modify the behavior of the parser to aggregate the row itself, but if I go down that route, why not just have the parser aggregate the entire file? (Answer: it shouldn't)
我今天尝试使用这个,基于@DaveDeLong 的优秀答案和代码,但我认为自他(2010)的答案以来该软件已经被修改。在撰写本文时,我发现我必须使用这个:
即
parser:didStartLine:lineNumber:
已变为parser:didBeginLine:lineNumber:
和parser: didReadField:
已变为parser:didReadField:atIndex:
。I tried using this today, based on @DaveDeLong's excellent answer and code, but I think the software has been revised since his (2010) answer. At the time of writing, I found I had to use this:
i.e.,
parser:didStartLine:lineNumber:
has becomeparser:didBeginLine:lineNumber:
andparser:didReadField:
has becomeparser:didReadField:atIndex:
.要将 CHCSVParser 与 Swift 结合使用,您可以使用一个 swift 包装器来满足基本需求
To use CHCSVParser with Swift you can use a swift wrapper for basic needs