这让我很难过。我正在尝试逐行读取 iOS 上的 6MB CSV 文件。我尝试过使用纯 C 文件指针和 NSInputStream 轮询,但选择了以下感觉最干净的方法。所有这三种方法都会导致看似随机的读取块返回成功,但会用所有空字节填充缓冲区。我说“随机”,但它具有一致性。重新运行程序时,读取在完全相同的点停止工作,并且读取的数量是可疑的(更多内容见下文)。
- (id)initWithFileAtPath:(NSString *)path {
if ((self = [super init])) {
filePath = [path copy];
queue = [[NSOperationQueue alloc] init];
queue.maxConcurrentOperationCount = 1;
buffer = [[NSMutableString alloc] init];
bytes = malloc(CHUNK_SIZE * sizeof(UTF8Char));
}
return self;
}
- (void)dealloc {
[filePath release];
[queue release];
[buffer release];
free(bytes);
[super dealloc];
}
- (void)stream:(NSInputStream *)stream handleEvent:(NSStreamEvent)eventCode {
switch (eventCode) {
case NSStreamEventOpenCompleted:
break;
case NSStreamEventHasBytesAvailable:
[queue addOperationWithBlock:^{
[self readChunk: stream];
[self drainBuffer];
}];
break;
case NSStreamEventEndEncountered:
if ([buffer length] > 0) {
[delegate reader:self didReadLine:[NSString stringWithString:buffer]];
[buffer setString:@""];
}
[stream close];
[stream removeFromRunLoop:[NSRunLoop currentRunLoop]
forMode:NSDefaultRunLoopMode];
[stream release];
[delegate readerDidFinishReading:self];
break;
default:
NSLog(@"StreamReader: event %d", eventCode);
break;
}
}
- (void)enumerateLines {
NSInputStream *stream = [[NSInputStream alloc] initWithFileAtPath:filePath];
stream.delegate = self;
[stream scheduleInRunLoop:[NSRunLoop currentRunLoop]
forMode:NSDefaultRunLoopMode];
[stream open];
}
- (void)readChunk: (NSInputStream*)stream {
NSInteger readSize = [stream read:bytes maxLength:CHUNK_SIZE];
if (readSize) {
if (bytes[0] == '\0') {
NSLog(@"null buffer %d", readSize);
}
NSString *string = [[NSString alloc] initWithBytes:bytes
length:readSize
encoding:NSUTF8StringEncoding];
[buffer appendString:string];
[string release];
} else {
NSLog(@"StreamReader: read zero bytes");
}
}
- (void)drainBuffer {
static NSCharacterSet *newlines = nil;
if (newlines == nil) {
newlines = [NSCharacterSet newlineCharacterSet];
}
NSRange newlinePos;
while ((newlinePos = [buffer rangeOfCharacterFromSet:newlines]).location != NSNotFound) {
NSString *line = [buffer substringToIndex:newlinePos.location];
// remove the line from the buffer along with line separator
[buffer deleteCharactersInRange: (NSRange){0, [line length]}];
while ([buffer length] > 0 && [newlines characterIsMember:[buffer characterAtIndex:0]]) {
[buffer deleteCharactersInRange:(NSRange){0, 1}];
}
[delegate reader:self didReadLine: line];
}
}
在读取 6MB 文件时,当 CHUNK_SIZE 为 1024 时,我将获得一系列 96 次“错误读取”。如果 CHUNK_SIZE 为 512,则会出现一系列 192 次“错误读取”。我所说的“坏读”是什么意思?NSInputStream 读取消息返回成功,委托回调中没有错误事件发生。然而bytes
缓冲区具有所有空值。
- iOS 7.0.4,iPad 2
- 不会发生在桌面上
- 在模拟器中不会发生
- 将文件大小减小到大约。1MB“修复”了 iPad 上的问题
最有可能值得注意的是,我在主 UI 线程上实例化了 reader 类。
所以......我在这里做错了什么微妙(或不微妙)吗?还是我发现了某种晦涩难懂的 iOS 错误?