2010-09-24 16 views
13

Son derece uzun bir .CSV dosyasıyla Dave DeLong'un mükemmel CHCSVParser objektifiyle oynuyorum ve bunu kullanırken bazı sorunlara yol açıyorum. arrayWithContentsOfCSVFile yöntemini kullanırdım, ancak bir iPhone'da kodu çalıştırıyorum ve tüm dosyayı belleğe ayrıştırmak mevcut olandan daha fazla bellek alacaktı.CHCSVParser sınıfını Kullanma

Aşağıdaki kodumda, çözümleyici belgeyi açar ve temsilci yöntemlerini mükemmel şekilde çağırır, ancak temsilci içinde her satırın ardından durabilir ve verilere erişebilir (bir Çekirdek Veri nesnesini veri deposuna oluşturmak ve kaydetmek için). ? Ben - (void) parser:(CHCSVParser *)parser didEndLine:(NSUInteger)lineNumber içinde olacağını varsayalım, ama hat ile bittiğinde ayrıştırıcıdan bir NSArray (veya her neyse) nasıl alabilirim?

İşte benim kod şimdiye kadar geçerli:

// 
// 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]); 
} 

teşekkürler!

cevap

17

Kodumun yararlı olduğunu gördüğüme sevindim! CHCSVParser, NSXMLParser numaralı davranışa benzer, çünkü her seferinde ilginç bir şey bulduğunda, bu temsilci geri bildirimlerinden birini bildirir. Ancak, geri bildirimde size verdiği verileri göz ardı etmeyi seçerseniz, o zaman yok olur. Bu ayrıştırıcılar (CHCSVParser ve NSXMLParser) oldukça aptaldır. Sadece ayrıştırmaya çalıştıkları şeylerin formatını biliyorlar, ancak bunun ötesinde pek bir şey yapmıyorlar. Bu nedenle cevap, kısaca, "kendiniz saklamanız gerekiyor" şeklindedir. NSArray kategorisine ait koda bakarsanız, .m dosyasında, a simple NSObject subclass as the parser delegate kullanıyor ve bu alt sınıf, alanları bir dizide toplayan ve ardından bu diziyi genel diziye ekleyen öğedir. Benzer bir şey yapmanız gerekecek.

Örnek temsilci: Ancak

@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 

, ben satır kendisi toplamak üzere ayrıştırıcı davranışını değiştirmeye ikna olabilirim, ama o rota inmek ise, neden sadece ayrıştırıcı agrega bütününü yok dosya? (Cevap: Olmaması gereken)

+0

Cevabınız için teşekkürler - Çözümleyicinin bu işi sizin için yapıp yapmadığını anlayamadım ('currentChunk' yoluyla veya başka bir yolla)! Toplamayı elle yapmak zorunda kalmamak güzel olurdu, ancak çoğu uygulama için CSV ayrıştırma gerçekten I/O için birkaç yerde kullanılır. Birisi bu küçük bir kodu bir kez yazmak isterse, alt sınıfın kullanılması mümkün olurdu veya CHCSVParserDelegate bir kategori yazmak? –

+0

@Neal 'CHCSVParserDelegate' bir protokoldür, bu yüzden onu alt sınıflara ayıramazsınız. Bu davranışı işe yaratabilmek için, doğrudan CHCSVParser'ı değiştirmeniz veya alt sınıfa ayırmanız gerekir. En basit cevap hattı kendiniz toplamaktır (cevabımda yaptığım gibi) –

+0

Öyle düşünmüyordun ... Buraya harika işler için tekrar çok teşekkürler! Aslında kodunuzda küçük bir düzeltme ... didEndLine'da "currentLine" ı "currentRow" olarak değiştirmemiz gerekiyor. (değiştirdim ama yeterli XP yok;)) –

1

Bugün, DaveDeLong'un mükemmel cevabı ve koduna dayanarak bunu kullanmayı denedim, ancak yazılımın (2010) yanıtından bu yana revize edildiğini düşünüyorum.

@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 

yani parser:didStartLine:lineNumber:parser:didBeginLine:lineNumber: haline gelmiştir ve parser:didReadField:parser:didReadField:atIndex: haline gelmiştir: Yazım sırasında, ben bu kullanmak zorunda bulundu.

İlgili konular