Hallo,
ich möchte in meiner Anwendung große CSV-Dateien verarbeiten können. Da ich den Parser nicht komplett selber schreiben möchte habe ich folgenden verwendet:
github.com/davedelong/CHCSVParser
Dann wollte ich zur Übersicht (und weil ich damit noch nicht so viel Erfahrung habe) den CSV-Parse-Vorgang über Blocks steuern.
Das ganze funktioniert wie es soll, nur leider habe ich das Problem wenn ich eine 88MB CSV einlese wird der Speicher während der Verarbeitung nicht freigegeben. Die Kurve bei Memory steigt also stetig an...
Um das ganze zu testen habe ich eine kleine Testanwendung gebaut.
Der CSV-Parser sieht nun wie folgt aus:
.h
Alles anzeigen
.m
Alles anzeigen
Aufgerufen wird das ganze wie folgt - wie gesagt ist erstmal zu Testzwecken
Alles anzeigen
Die ganzen @autorelease sind mehr oder weniger ein Versuch gewesen das Problem zu lösen... leider ohne Erfolg
Kann mir hier jemand weiterhelfen?
ich möchte in meiner Anwendung große CSV-Dateien verarbeiten können. Da ich den Parser nicht komplett selber schreiben möchte habe ich folgenden verwendet:
github.com/davedelong/CHCSVParser
Dann wollte ich zur Übersicht (und weil ich damit noch nicht so viel Erfahrung habe) den CSV-Parse-Vorgang über Blocks steuern.
Das ganze funktioniert wie es soll, nur leider habe ich das Problem wenn ich eine 88MB CSV einlese wird der Speicher während der Verarbeitung nicht freigegeben. Die Kurve bei Memory steigt also stetig an...
Um das ganze zu testen habe ich eine kleine Testanwendung gebaut.
Der CSV-Parser sieht nun wie folgt aus:
.h
Quellcode
- @class CHCSVParser;
- @interface SAMOACSVParser : NSObject
- @property (assign, nonatomic) BOOL recognizesBackslashesAsEscapes; // default is NO
- @property (assign, nonatomic) BOOL sanitizesFields;
- @property (assign, nonatomic) BOOL stripsLeadingAndTrailingWhitespace; // default is NO
- //> define callback blocks
- typedef void (^CSVDocumentBegin) (CHCSVParser *parser);
- typedef void (^CSVDocumentEnd) (CHCSVParser *parser);
- typedef void (^CSVBeginLine) (CHCSVParser *parser, NSUInteger lineNumber);
- typedef void (^CSVEndLine) (CHCSVParser *parser, NSUInteger lineNumber);
- typedef void (^CSVReadField) (CHCSVParser *parser, NSUInteger fieldIndex, NSString *fieldValue);
- typedef void (^CSVFailed) (CHCSVParser *parser, NSError *error);
- - (id)initWithFileAtPath:(NSString*)filePath useEncoding:(NSStringEncoding)encoding useDelimiter:(NSString*)delimiter areFieldsEscaped:(BOOL)escaped;
- - (void)start:(CSVDocumentBegin)docBegin docEnded:(CSVDocumentEnd)docEnd lineBegin:(CSVBeginLine)beginLine lineEnd:(CSVEndLine)endLine readField:(CSVReadField)fieldRead failed:(CSVFailed)failed;
- @end
.m
Quellcode
- //
- // SAMOACSVParser.m
- // SAMOA
- //
- // Created by Heiko on 07.02.14.
- // Copyright (c) 2014 Kommdirekt GmbH. All rights reserved.
- //
- #import "SAMOACSVParser.h"
- @interface SAMOACSVParser () <CHCSVParserDelegate>
- @property (assign, nonatomic) NSStringEncoding csvEncoding;
- @property (assign, nonatomic) unichar csvDelimiter;
- @property (strong, nonatomic) NSString *csvFilePath;
- //> callbacks
- @property (copy) CSVDocumentBegin cbBeginDoc;
- @property (copy) CSVDocumentEnd cbEndDoc;
- @property (copy) CSVBeginLine cbBeginLine;
- @property (copy) CSVEndLine cbEndLine;
- @property (copy) CSVReadField cbReadField;
- @property (copy) CSVFailed cbFailed;
- @end
- @implementation SAMOACSVParser
- -(id)initWithFileAtPath:(NSString *)filePath useEncoding:(NSStringEncoding)encoding useDelimiter:(NSString *)delimiter areFieldsEscaped:(BOOL)escaped {
- if (filePath==nil) {
- return nil;
- }
- self = [super init];
- if (self) {
- BOOL isDir;
- if ([FileManager fileExistsAtPath:filePath isDirectory:&isDir]) {
- if (isDir==NO) {
- //> csv file Exist
- self.csvFilePath = filePath;
- self.csvEncoding = encoding;
- self.csvDelimiter = [delimiter characterAtIndex:0];
- self.sanitizesFields = escaped;
- self.recognizesBackslashesAsEscapes = NO;
- self.stripsLeadingAndTrailingWhitespace = NO;
- return self;
- }
- }
- }
- return nil;
- }
- - (void)start:(CSVDocumentBegin)docBegin docEnded:(CSVDocumentEnd)docEnd lineBegin:(CSVBeginLine)beginLine lineEnd:(CSVEndLine)endLine readField:(CSVReadField)fieldRead failed:(CSVFailed)failed {
- //> init callback blocks
- self.cbBeginDoc = docBegin;
- self.cbEndDoc = docEnd;
- self.cbBeginLine = beginLine;
- self.cbEndLine = endLine;
- self.cbReadField = fieldRead;
- self.cbFailed = failed;
- dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
- @autoreleasepool {
- //> init chcsvparser
- NSInputStream *reader = [NSInputStream inputStreamWithFileAtPath:self.csvFilePath];
- NSStringEncoding encoding = self.csvEncoding;
- CHCSVParser *csvParser = [[CHCSVParser alloc] initWithInputStream:reader usedEncoding:&encoding delimiter:self.csvDelimiter];
- csvParser.delegate = self;
- csvParser.sanitizesFields = self.sanitizesFields;
- csvParser.recognizesBackslashesAsEscapes = self.recognizesBackslashesAsEscapes;
- csvParser.recognizesComments = NO;
- csvParser.stripsLeadingAndTrailingWhitespace = self.stripsLeadingAndTrailingWhitespace;
- // start Parser
- [csvParser parse];
- }
- });
- }
- #pragma mark -
- #pragma mark PARSER Delegates
- #pragma mark -
- -(void)parserDidBeginDocument:(CHCSVParser *)parser {
- self.cbBeginDoc(parser);
- }
- -(void)parserDidEndDocument:(CHCSVParser *)parser {
- self.cbEndDoc(parser);
- }
- -(void)parser:(CHCSVParser *)parser didBeginLine:(NSUInteger)recordNumber {
- @autoreleasepool {
- self.cbBeginLine(parser, recordNumber);
- }
- }
- -(void)parser:(CHCSVParser *)parser didEndLine:(NSUInteger)recordNumber {
- @autoreleasepool {
- self.cbEndLine(parser, recordNumber);
- }
- }
- -(void)parser:(CHCSVParser *)parser didReadField:(NSString *)field atIndex:(NSInteger)fieldIndex {
- @autoreleasepool {
- self.cbReadField(parser, fieldIndex, field);
- }
- }
- -(void)parser:(CHCSVParser *)parser didFailWithError:(NSError *)error {
- self.cbFailed(parser, error);
- }
- @end
Aufgerufen wird das ganze wie folgt - wie gesagt ist erstmal zu Testzwecken
Quellcode
- @autoreleasepool {
- //> Block Vars
- __block NSMutableArray *row;
- NSString *csvPath = [[File getDocPath] stringByAppendingPathComponent:@"Test.csv"];
- SAMOACSVParser *parser = [[SAMOACSVParser alloc] initWithFileAtPath:csvPath useEncoding:NSUTF8StringEncoding useDelimiter:@"," areFieldsEscaped:YES];
- parser.recognizesBackslashesAsEscapes = YES;
- parser.stripsLeadingAndTrailingWhitespace = YES;
- [parser start:^(CHCSVParser *parser){
- NSLog(@"Start Doc");
- [Utils startTimer];
- }
- docEnded:^(CHCSVParser *parser){
- NSLog(@"End Doc");
- [Utils stopTimer];
- }
- lineBegin:^(CHCSVParser *parser, NSUInteger line){
- //NSLog(@"Start: %i", line);
- row = [NSMutableArray new];
- }
- lineEnd:^(CHCSVParser *parser, NSUInteger line){
- NSLog(@"ROW-Output: %@", [row componentsJoinedByString:@"!!"]);
- row = nil;
- }
- readField:^(CHCSVParser *parser, NSUInteger fieldIndex, NSString *value){
- [row addObject:value];
- }
- failed:^(CHCSVParser *parser, NSError *parserError){
- NSLog(@"Parser Failed: %@", parserError);
- }];
- }
Die ganzen @autorelease sind mehr oder weniger ein Versuch gewesen das Problem zu lösen... leider ohne Erfolg

Kann mir hier jemand weiterhelfen?
