如何在iPhone上读取大型UTF-8文件?

Phi*_*ard 12 iphone objective-c ios

我的应用程序以UTF-8格式下载文件,该文件太大而无法使用该NSString initWithContentsOfFile方法读取.我NSFileHandle readDataOfLength遇到的问题是该方法读取指定数量的字节,我可能最终只读取UTF-8字符的一部分.这里最好的解决方案是什么?

后来:

让它记录在船舶的日志中,以下代码有效:

    NSData *buf = [NSData dataWithContentsOfFile:path
                                      options:NSDataReadingMappedIfSafe
                                        error:nil];

NSString *data = [[[NSString alloc] 
                   initWithBytesNoCopy:(void *)buf.bytes 
                   length:buf.length 
                   encoding:NSUTF8StringEncoding 
                   freeWhenDone:NO] autorelease];
Run Code Online (Sandbox Code Playgroud)

我的主要问题实际上是编码,而不是读取文件的任务.

Tom*_*mmy 13

您可以使用NSData +dataWithContentsOfFile:options:error:NSDataReadingMappedIfSafe选项映射文件内存,而不是加载它.这样就可以使用iOS中的虚拟内存管理器来确保文件的各个部分以与桌面操作系统处理其磁盘上虚拟内存文件相同的方式交换进RAM.因此,您不需要足够的RAM来将整个文件保存在内存中,您只需要将文件足够小以适应处理器的地址空间(因此,千兆字节).您将获得一个与正常情况完全相同的对象NSData,这可以为您节省大部分与使用NSFileHandle和手动流相关的麻烦.

您可能需要转换部分,NSString因为您可以真实地期望从UTF-8转换为另一种格式(尽管它可能不会;值得一试,-initWithData:encoding:看看NSString是否足够智能只是为了保持对原始数据,并根据需要从UTF-8扩展),我认为这是你的问题真正得到的.

我建议您使用-initWithBytes:length:encoding:将合理数量的字节转换为字符串.然后,您可以使用它-lengthOfBytesUsingEncoding:来确定它实际意义上的字节数并适当地提前读取指针.这是一个安全的假设,NSString它将丢弃您提供的字节末尾的任何部分字符.

编辑:所以,像:

// map the file, rather than loading it
NSData *data = [NSData dataWithContentsOfFile:...whatever...
                         options:NSDataReadingMappedIfSafe
                         error:&youdDoSomethingSafeHere];

// we'll maintain a read pointer to our current location in the data
NSUinteger readPointer = 0;

// continue while data remains
while(readPointer < [data length])
{
    // work out how many bytes are remaining
    NSUInteger distanceToEndOfData = [data length] - readPointer;

    // grab at most 16kb of them, being careful not to read too many
    NSString *newPortion = 
         [[NSString alloc] initWithBytes:(uint8_t *)[data bytes] + readPointer
                 length:distanceToEndOfData > 16384 ? 16384 : distanceToEndOfData
                 encoding:NSUTF8StringEncoding];

    // do whatever we want with the string
    [self doSomethingWithFragment:newPortion];

    // advance our read pointer by the number of bytes actually read, and
    // clean up
    readPointer += [newPortion lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
    [newPortion release];
}
Run Code Online (Sandbox Code Playgroud)

当然,一个隐含的假设是所有UTF-8编码都是唯一的,我不得不承认这些编码不足以说明绝对确定.