2010-09-24 34 views
13

tôi đang chơi xung quanh với Dave DeLong tuyệt vời CHCSVParser cho Objective-C với một tập tin CSV rất lâu và đang chạy vào một số vấn đề khi dùng nó. Tôi sẽ sử dụng phương pháp arrayWithContentsOfCSVFile, nhưng tôi đang chạy mã trên iPhone và phân tích toàn bộ tệp vào bộ nhớ sẽ chiếm nhiều bộ nhớ hơn khả dụng.Làm thế nào để sử dụng các lớp CHCSVParser

Trong mã của tôi dưới đây, trình phân tích mở tài liệu và gọi phương thức đại biểu một cách hoàn hảo, nhưng trong đại biểu nào tôi dừng sau mỗi dòng và truy cập dữ liệu (để tạo và lưu đối tượng Dữ liệu cốt lõi vào kho dữ liệu) ? Tôi cho rằng đó sẽ là trong - (void) parser:(CHCSVParser *)parser didEndLine:(NSUInteger)lineNumber, nhưng làm thế nào để tôi nhận được một NSArray (hoặc bất kỳ) của các dữ liệu từ các phân tích cú pháp khi nó được thực hiện với dòng?

Đây là mã của tôi cho đến nay:

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

Cảm ơn!

Trả lời

17

Tôi rất vui khi thấy rằng mã của tôi được chứng minh hữu ích! :)

CHCSVParser tương tự về hành vi đối với một NSXMLParser, trong đó mỗi lần tìm thấy điều gì đó thú vị, nó sẽ cho bạn biết qua một trong các cuộc gọi lại của người được ủy quyền. Tuy nhiên, nếu bạn chọn bỏ qua dữ liệu mà nó cung cấp cho bạn trong cuộc gọi lại, thì nó sẽ biến mất. Những trình phân tích cú pháp này (CHCSVParserNSXMLParser) khá ngu ngốc. Họ chỉ biết định dạng của những thứ họ đang cố gắng phân tích, nhưng không thực sự vượt xa điều đó.

Vì vậy, câu trả lời, trong Tóm lại, là "bạn phải lưu nó cho mình". Nếu bạn nhìn vào các mã cho loại NSArray, bạn sẽ thấy trong file .m rằng nó sử dụng a simple NSObject subclass as the parser delegate, và lớp con đó là những gì đang tập hợp các lĩnh vực vào một mảng, và sau đó thêm rằng mảng đến các mảng tổng thể. Bạn sẽ cần phải làm một cái gì đó tương tự.

Ví dụ đại biểu:

@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 

Tuy nhiên, tôi có thể được thuyết phục để thay đổi hành vi của các phân tích cú pháp để tổng hợp hàng riêng của mình, nhưng nếu tôi đi xuống con đường đó, tại sao không chỉ có phân tích cú pháp tổng hợp toàn bộ tập tin? (Trả lời: không nên)

+0

Cảm ơn cho câu trả lời - Tôi không thể nói nếu phân tích cú pháp đã làm công việc này cho bạn (qua 'currentChunk' hoặc một số cách khác)! Nó sẽ được tốt đẹp không phải tự làm các tập hợp, nhưng đối với hầu hết các ứng dụng CSV phân tích chỉ thực sự được sử dụng trong một vài nơi cho I/O.Nếu ai đó muốn viết rằng ít bit một lần, nó sẽ có thể để phân lớp hoặc viết một danh mục trên CHCSVParserDelegate? –

+0

@Neal 'CHCSVParserDelegate' là giao thức, vì vậy bạn không thể phân lớp nó. Để làm cho hành vi này hoạt động, bạn phải thay đổi 'CHCSVParser' trực tiếp hoặc phân lớp nó. Câu trả lời đơn giản nhất là tổng hợp dòng (như tôi làm trong câu trả lời) –

+0

Không nghĩ vậy ... Cảm ơn rất nhiều lần vì công việc tuyệt vời ở đây! Trên thực tế, một sửa đổi nhỏ cho mã của bạn ... trong 'didEndLine', chúng ta cần thay đổi' currentLine' thành 'currentRow'. (Tôi muốn thay đổi nó nhưng không có đủ XP;)) –

1

Tôi đã thử sử dụng ngày hôm nay, dựa trên câu trả lời và mã xuất sắc của @ DaveDeLong, nhưng tôi nghĩ phần mềm đã được sửa đổi kể từ câu trả lời của anh ấy (2010). Tại thời điểm viết bài, tôi thấy tôi đã phải sử dụng này:

@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 

ví dụ: parser:didStartLine:lineNumber: đã trở thành parser:didBeginLine:lineNumber:parser:didReadField: đã trở thành parser:didReadField:atIndex:.

Các vấn đề liên quan