iOS读取文件闪退

iOS读取文件闪退

问题

读取本地文件时出现内存暴涨,闪退等情况,报错信息如下

malloc: can't allocate region *** mach_vm_map(size=1404370944) failed (error code=3) UploadDemo(3736,0x1006cabc0) malloc: *** set a breakpoint in malloc_error_break to debug

读取问价你的代码如下

+ (NSData *)fileData:(NSString *)filePath {
    /**
     //闪退
     NSError *readError;
     NSFileHandle *fileHande = [NSFileHandle fileHandleForReadingFromURL:[NSURL URLWithString:filePath] error:&readError];
     if (!readError) {
     NSData *readData = [fileHande readDataToEndOfFile];
     [fileHande closeFile];
     return readData;
     }
     //闪退
     NSFileHandle *fileHande = [NSFileHandle fileHandleForReadingAtPath:filePath];
     return [fileHande readDataToEndOfFile];
     */
    //也闪退
    NSFileHandle *fileHande = [NSFileHandle fileHandleForReadingAtPath:filePath];
    return [fileHande availableData];
}

分析

纳闷为什么读大文件,尤其是视频文件的时候内存会暴涨的话,拍一下自己就明白了。

发现读取大文件的时候,尤其是视频文件时,App的内存暴涨?为什么会这样呢?

后来我想明白了,暴涨就对了,内存不涨那次有问题呢。文件在磁盘上存储着,当我们读取它的时候,会将读到的数据放到缓存里,手机的缓存是有限,但是文件很大,所以内存会暴涨,而且直接卡爆,然后报limit xx m的错误。

把文件从磁盘读出来,然后再存储到别的地方,这种思想就很可怕,读出来整个文件那得占用多大的缓存啊。这个把文件都读出来,然后再写入的思想本来就是不对的。

正确的做法应该是,循环读取,每次读小一部分数据,然后写入文件,直到把整个文件读完保存完。

解决

有种方式叫做”另存位“或者叫”文件拷贝“吧,先把文件拷贝到另一个地方,然后分片处理这些数据。

#pragma mark - 文件操作

int32_t const VH_CHUNK_SIZE = 8 * 1024;

//另存为
- (NSString *)writefile:(NSString *)filePath
{
    //写入文件路径
    NSString *toPath = [NSString stringWithFormat:@"%@/%@",NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES).firstObject,[filePath lastPathComponent]];
    //如果存在,先删除
    if ([[NSFileManager defaultManager] fileExistsAtPath:toPath]) {
        [[NSFileManager defaultManager] removeItemAtPath:toPath error:nil];
    }
    //创建文件路径
    if (![[NSFileManager defaultManager] createFileAtPath:toPath contents:nil attributes:nil]) {
        return nil;
    }
    //打开文件
    NSFileHandle *sourceHandle = [NSFileHandle fileHandleForReadingAtPath:filePath];
    NSFileHandle *writeHandle = [NSFileHandle fileHandleForWritingAtPath:toPath];
    if(sourceHandle == nil || writeHandle == nil) {
        return nil;
    }
    //读取文件写入
    BOOL done = NO;
    while(!done) {
        @autoreleasepool{
            NSData *data = [sourceHandle readDataOfLength:VH_CHUNK_SIZE];
            if([data length] == 0) {
                done = YES;
            }
            [writeHandle seekToEndOfFile];
            [writeHandle writeData:data];
            data = nil;
        }
    }
    //关闭文件
    [sourceHandle closeFile];
    [writeHandle closeFile];
    return toPath;
}
//删除本地上传的文件
- (BOOL)deletefile:(NSString *)uploadPath {
    if ([[NSFileManager defaultManager] fileExistsAtPath:uploadPath]) {
        BOOL removed = [[NSFileManager defaultManager] removeItemAtPath:uploadPath error:nil];
        return removed;
    }
    return NO;
}

结论

为什么要把整个文件都读出来,然后再去做别的事情,这种思想本身就陷入了一个坑。手机内存有限,不能一次性把较大的数据读出来。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Morris_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值