Created
May 24, 2011 03:57
-
-
Save cmkilger/988122 to your computer and use it in GitHub Desktop.
Dave's DDFileReader class
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* Dave's DDFileReader from http://stackoverflow.com/questions/3707427/how-to-read-data-from-nsfilehandle-line-by-line */ | |
//DDFileReader.h | |
@interface DDFileReader : NSObject { | |
NSString * filePath; | |
NSFileHandle * fileHandle; | |
unsigned long long currentOffset; | |
unsigned long long totalFileLength; | |
NSString * lineDelimiter; | |
NSUInteger chunkSize; | |
} | |
@property (nonatomic, copy) NSString * lineDelimiter; | |
@property (nonatomic) NSUInteger chunkSize; | |
- (id) initWithFilePath:(NSString *)aPath; | |
- (NSString *) readLine; | |
- (NSString *) readTrimmedLine; | |
#if NS_BLOCKS_AVAILABLE | |
- (void) enumerateLinesUsingBlock:(void(^)(NSString*, BOOL *))block; | |
#endif | |
@end | |
//DDFileReader.m | |
#import "DDFileReader.h" | |
@interface NSData (DDAdditions) | |
- (NSRange) rangeOfData_dd:(NSData *)dataToFind; | |
@end | |
@implementation NSData (DDAdditions) | |
- (NSRange) rangeOfData_dd:(NSData *)dataToFind { | |
const void * bytes = [self bytes]; | |
NSUInteger length = [self length]; | |
const void * searchBytes = [dataToFind bytes]; | |
NSUInteger searchLength = [dataToFind length]; | |
NSUInteger searchIndex = 0; | |
NSRange foundRange = {NSNotFound, searchLength}; | |
for (NSUInteger index = 0; index < length; index++) { | |
if (((char *)bytes)[index] == ((char *)searchBytes)[searchIndex]) { | |
//the current character matches | |
if (foundRange.location == NSNotFound) { | |
foundRange.location = index; | |
} | |
searchIndex++; | |
if (searchIndex >= searchLength) { return foundRange; } | |
} else { | |
searchIndex = 0; | |
foundRange.location = NSNotFound; | |
} | |
} | |
return foundRange; | |
} | |
@end | |
@implementation DDFileReader | |
@synthesize lineDelimiter, chunkSize; | |
- (id) initWithFilePath:(NSString *)aPath { | |
if (self = [super init]) { | |
fileHandle = [NSFileHandle fileHandleForReadingAtPath:aPath]; | |
if (fileHandle == nil) { | |
[self release]; return nil; | |
} | |
lineDelimiter = [[NSString alloc] initWithString:@"\n"]; | |
[fileHandle retain]; | |
filePath = [aPath retain]; | |
currentOffset = 0ULL; | |
chunkSize = 10; | |
[fileHandle seekToEndOfFile]; | |
totalFileLength = [fileHandle offsetInFile]; | |
//we don't need to seek back, since readLine will do that. | |
} | |
return self; | |
} | |
- (void) dealloc { | |
[fileHandle closeFile]; | |
[fileHandle release], fileHandle = nil; | |
[filePath release], filePath = nil; | |
[lineDelimiter release], lineDelimiter = nil; | |
currentOffset = 0ULL; | |
[super dealloc]; | |
} | |
- (NSString *) readLine { | |
if (currentOffset >= totalFileLength) { return nil; } | |
NSData * newLineData = [lineDelimiter dataUsingEncoding:NSUTF8StringEncoding]; | |
[fileHandle seekToFileOffset:currentOffset]; | |
NSMutableData * currentData = [[NSMutableData alloc] init]; | |
BOOL shouldReadMore = YES; | |
NSAutoreleasePool * readPool = [[NSAutoreleasePool alloc] init]; | |
while (shouldReadMore) { | |
if (currentOffset >= totalFileLength) { break; } | |
NSData * chunk = [fileHandle readDataOfLength:chunkSize]; | |
NSRange newLineRange = [chunk rangeOfData_dd:newLineData]; | |
if (newLineRange.location != NSNotFound) { | |
//include the length so we can include the delimiter in the string | |
chunk = [chunk subdataWithRange:NSMakeRange(0, newLineRange.location+[newLineData length])]; | |
shouldReadMore = NO; | |
} | |
[currentData appendData:chunk]; | |
currentOffset += [chunk length]; | |
} | |
[readPool release]; | |
NSString * line = [[NSString alloc] initWithData:currentData encoding:NSUTF8StringEncoding]; | |
[currentData release]; | |
return [line autorelease]; | |
} | |
- (NSString *) readTrimmedLine { | |
return [[self readLine] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; | |
} | |
#if NS_BLOCKS_AVAILABLE | |
- (void) enumerateLinesUsingBlock:(void(^)(NSString*, BOOL*))block { | |
NSString * line = nil; | |
BOOL stop = NO; | |
while (stop == NO && (line = [self readLine])) { | |
block(line, &stop); | |
} | |
} | |
#endif | |
@end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment