美文网首页iOS开发iOS Developer
iOS 文件管理器与性能提升

iOS 文件管理器与性能提升

作者: zaijianbali | 来源:发表于2017-05-23 20:54 被阅读201次

    写一个文件管理器并不难,难在如何提升性能?

    文件管理器无非就是增删改查

    本文的重点在于删和查的新能提升。
    普通的目录,我们删除或者查询一个或者多个很快,但如果这个目录文件量达到
    举个例子:
    1.文件如何归类存储
    2.查询目录下超过三个月未访问的文件大小
    3.删除超过三个月未访问的文件

    针对归类存储,我们的策略很简单,就是语音、图片放到不同的目录下:

    /**
    *  @brief  视频文件目录的路径
    *
    *  @return 视频目录路径
    */
    + (NSString *)videoPath;
    
    /**
    *  @brief  图片文件目录的路径
    *
    *  @return 图片目录路径
    */
    + (NSString *)imagePath;
    
    /**
    *  @brief  音频目录路径
    *
    *  @return 音频目录路径
    */
    + (NSString *)audioPath;
    

    针对第二个问题:查询目录下超过三个月未访问的文件大小
    我们提供了如下接口:

    
    /**
    *  @brief  删除图片文件缓存
    *
    *  @return 删除成功失败
    */
    + (BOOL)deleteCachedImages;
    + (BOOL)deleteCachedImagesFor3MonthAgo;
    
    /**
    *  @brief  删除音频文件缓存
    *
    *  @return 删除成功失败
    */
    + (BOOL)deleteCachedAudioes;
    + (BOOL)deleteCachedAudioesFor3MonthAgo;
    
    /**
    *  @brief  删除视频文件缓存
    *
    *  @return 删除成功失败
    */
    + (BOOL)deleteCachedVideoes;
    + (BOOL)deleteCachedVideoesFor3MonthAgo;
    
    /**
    *  @brief  删除3个月前的图片、语音、视频数据
    */
    + (BOOL)deleteCachedForderFor3MonthAgo;
    /**
    *  @brief  删除图片、语音、视频数据
    */
    + (BOOL)deleteCachedForder;
    
    

    关于第三个问题:删除超过三个月未访问的文件
    我们提供接口如下:

    /**
     *  @brief  图片文件夹大小,单位字节B(Byte)
     */
    + (int64_t)imageFolderSize;
    
    /**
     *  @brief  音频文件夹大小,单位字节B(Byte)
     */
    + (int64_t)audioFolderSize;
    
    /**
     *  @brief  视频文件夹大小,单位字节B(Byte)
     */
    + (int64_t)videoFolderSize;
    
    /**
     *  三个月前的图片、语音、视频文件大小,单位字节B(Byte)
     */
    + (int64_t)folderSizeFor3MonthAgo;
    /**
     * 图片、语音、视频的文件大小,单位字节B(Byte)
     */
    + (int64_t)cachedFolderSize;
    
    /**
     *  @brief  系统总容量,单位:B
     */
    + (float)totalDiskSpace;
    
    /**
     *  @brief  系统剩余可用空间大小,单位:B
     */
    + (float)freeDiskSpace;
    
    /**
     *  @brief  当前应用使用的硬盘空间,耗时操作,单位:B
     */
    + (float)appUsedSpace;
    
    

    分割线


    下面说说性能,一般情况下为了方便:我们都是用OC代码写,但OC是基于C的封装,我们看看OC如何访问文件的。

        // 方法1:使用NSFileManager来实现获取文件大小
    + (long long)fileSizeAtPath1:(NSString *)filePath{
        NSFileManager* manager = [NSFileManager defaultManager];
        if ([manager fileExistsAtPath:filePath]){
            return [[manager attributesOfItemAtPath:filePath error:nil] fileSize];
        }
        return 0;
    }
    
        // 方法1:使用unix c函数来实现获取文件大小
    + (long long)fileSizeAtPath2:(NSString *)filePath{
        struct stat st;
        if(lstat([filePath cStringUsingEncoding:NSUTF8StringEncoding], &st) == 0){
            return st.st_size;
        }
        return 0;
    }
    #pragma mark 获取目录大小
    
    
        //实测 :1000个文件 读取 平均时间为:0.079914
        // 方法1:循环调用fileSizeAtPath1
    + (long long)folderSizeAtPath1:(NSString *)folderPath{
        CFAbsoluteTime startTime =CFAbsoluteTimeGetCurrent();
        NSFileManager* manager = [NSFileManager defaultManager];
        if (![manager fileExistsAtPath:folderPath]) return 0;
        NSEnumerator *childFilesEnumerator = [[manager subpathsAtPath:folderPath] objectEnumerator];
        NSString* fileName;
        long long folderSize = 0;
        while ((fileName = [childFilesEnumerator nextObject]) != nil){
            NSString* fileAbsolutePath = [folderPath stringByAppendingPathComponent:fileName];
            folderSize += [self fileSizeAtPath1:fileAbsolutePath];
        }
        CFAbsoluteTime endTime =CFAbsoluteTimeGetCurrent();
        NSLog(@"ttttttttttt:%s,%f,%lld",__func__,endTime-startTime,folderSize);
        return folderSize;
    }
    
        // 1000个文件平均时间为:0.02653
        // 方法2:循环调用fileSizeAtPath2
    + (long long)folderSizeAtPath2:(NSString *)folderPath{
        TICK
        NSFileManager* manager = [NSFileManager defaultManager];
        if (![manager fileExistsAtPath:folderPath]) return 0;
        NSEnumerator *childFilesEnumerator = [[manager subpathsAtPath:folderPath] objectEnumerator];
        NSString* fileName;
        long long folderSize = 0;
        while ((fileName = [childFilesEnumerator nextObject]) != nil){
            NSString* fileAbsolutePath = [folderPath stringByAppendingPathComponent:fileName];
            folderSize += [self fileSizeAtPath2:fileAbsolutePath];
        }
        TOCK
        return folderSize;
    }
    
    

    再来看看如何用c写,其性能如何

        // 方法3:完全使用unix c函数 性能最好
        //实测  1000个文件速度 0.005896
    + (int64_t)folderSizeAtPath:(const char *)folderPath maxTime:(NSNumber *)maxTime{
    
        CFAbsoluteTime startTime =CFAbsoluteTimeGetCurrent();
    
        int64_t folderSize = 0;
        DIR* dir = opendir(folderPath);
    
    
        if (dir == NULL) return 0;
        struct dirent* child;
        while ((child = readdir(dir))!=NULL) {
            if (child->d_type == DT_DIR && (
                                            (child->d_name[0] == '.' && child->d_name[1] == 0) || // 忽略目录 .
                                            (child->d_name[0] == '.' && child->d_name[1] == '.' && child->d_name[2] == 0) // 忽略目录 ..
                                            )) continue;
    
            int64_t folderPathLength = strlen(folderPath);
    
            // 子文件的路径地址
            char childPath[1024];
            stpcpy(childPath, folderPath);
    
            if (folderPath[folderPathLength-1] != '/') {
                childPath[folderPathLength] = '/';
                folderPathLength++;
            }
    
            stpcpy(childPath+folderPathLength, child->d_name);
            childPath[folderPathLength + child->d_namlen] = 0;
    
            if (child->d_type == DT_DIR) { // directory
                // 递归调用子目录
                folderSize += [[self class] folderSizeAtPath:childPath maxTime:maxTime];
    
                // 把目录本身所占的空间也加上
                struct stat st;
                if(lstat(childPath, &st) == 0) folderSize += st.st_size;
            }else if (child->d_type == DT_REG || child->d_type == DT_LNK) { // file or link
                //特殊处理几个月前的内容
                if (maxTime) {
                    BOOL shouldCountSize = YES;
                    char *p = child->d_name;
                    NSString *fileName = [NSString stringWithCString:p encoding:NSUTF8StringEncoding];
                    NSComparisonResult result = [fileName compare:[maxTime stringValue]];
                    if (result == NSOrderedDescending)//小于三个月不统计
                    {
                        shouldCountSize = NO;
                    }
    
                    if (!shouldCountSize) {
                        continue;
                    }
                }
    
                struct stat st;
                if(lstat(childPath, &st) == 0) folderSize += st.st_size;
            }
        }
        CFAbsoluteTime endTime = CFAbsoluteTimeGetCurrent();
         NSLog(@"ttttttttttt:%s,%f,%lld",__func__,endTime-startTime,folderSize);
        return folderSize;
    }
    
    

    我们对比一下:
    同时访问同样的目录下的1000个文件的用时

    方法 用时
    方法1 使用NSFileManager 0.079914
    方法2 使用c函数 0.02653
    方法3 使用C底层函数 0.005896

    我们看对比:

    使用方法3的速度是方法1的 15倍,等于提升了一个数量级。

    最后我们还提供了:大小转换为合适的输出

    /**
     *  @brief  获取指定存储小数位数的浮点数,单位G,M,K  
     *   显示规则如下
     *      1.大于1G,转换为G单位的字符串+小数位数
     *      2.大于1M,则转化成M单位的字符串+ 小数位数
     *      3.不到1M,但是超过了1KB,则转化成KB单位+ 小数位数
     *      4.剩下的都是小于1K的,则转化成B单位
     *
     *  @param size          原值大小
     *  @param decimalplaces 指定小数位数大小
     *
     *  @return 获取指定存储小数位数的浮点数,单位G,M,K
     */
    + (NSString *)getStringWithStorage:(float)size decimalplaces:(NSInteger)decimalplaces;
    

    源码见github地址:WCFileController

    本文解释权归:子文

    如需转载请注明出处,谢谢

    来杯可乐催更吧

    请子文喝可乐

    相关文章

      网友评论

        本文标题:iOS 文件管理器与性能提升

        本文链接:https://www.haomeiwen.com/subject/enmgxxtx.html