iOS开发 - 文件读写数据缓存

对一些首页的网络加载的数据进行本地缓存,提升用户体验,不至于每次进入首页都是一片空白,这里使用的是文件读写的方式,直接将网络请求返回的json数据进行读写操作

YWDataCache.h文件

#import <Foundation/Foundation.h>

// 主缓存路径,默认放在 /Library/Caches/default 这个路径下
#define YWCachePath [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)[0] stringByAppendingString:@"/default"]
// 日志打印
#ifdef DEBUG
#   define YWLog(fmt, ...) NSLog((@"\n⭐️⭐️⭐️: %s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__);
#else
#   define YWLog(...)
#endif

@interface YWDataCache : NSObject

/**
 普通json缓存 - 写入缓存

 @param fileName        缓存文件名称(读取时保持一致)
 @param dataSource      要缓存的数据源
 @return                返回写入结果 YES Or NO
 */
+ (BOOL)writeDataToCacheWithFileName:(NSString *)fileName dataSource:(id)dataSource;

/**
 普通json缓存 - 读取缓存

 @param fileName        缓存文件名称(读写要保持一致)
 @return                返回读取结果
 */
+ (nullable id)getCacheWithFileName:(NSString *)fileName;

/**
 HTML缓存 - 写入缓存

 @param urlString       网页链接Url
 @return                返回写入结果 YES Or NO
 */
+ (BOOL)writeToHTMLCache:(NSString *)urlString;

/**
 HTML缓存 - 读取缓存

 @param urlString       网页链接Url
 @return                返回html标签文件
 */
+ (NSString *)getHTMLCacheWithUrlString:(NSString *)urlString;


/**
 *
 @param urlString       图片url
 @return                返回写入结果 YES Or NO
 */

/**
 网络图片缓存 - 写入缓存

 @param urlString       图片url
 @param successBlock    成功回调
 @param errorBlock      失败回调
 */
+ (void)writeImageToLocalCache:(NSString *)urlString successBlock:(void (^)(UIImage *))successBlock errorBlock:(void (^)(void))errorBlock;

/**
 网络图片缓存 - 读取缓存

 @param urlString       图片url
 @return                返回读取结果
 */
+ (UIImage *)getImageWithImageUrl:(NSString *)urlString;

/**
 获取path路径下文件夹的大小

 @param path            要获取的文件夹 路径
 @return                返回path路径下缓存文件大小
 */
+ (NSString *)getCacheSizeWithFilePath:(NSString *)path;

/**
 清除path路径下文件夹的缓存

 @param path            要清除缓存的文件夹 路径
 @return                返回是否清除成功
 */
+ (BOOL)clearCacheWithFilePath:(NSString *)path;


/**
 数据大小转换(bytes转 MB、KB、B)

 @param dataLength      数据长度
 @return                返回大小字符串
 */
+ (NSString *)getBytesFromDataLength:(NSInteger)dataLength;

@end

YWDataCache.m文件

#import "YWDataCache.h"
@implementation YWDataCache


#pragma mark - * * * * * 普通json缓存 * * * * *
// 普通json缓存 - 写入缓存
+ (BOOL)writeDataToCacheWithFileName:(NSString *)fileName dataSource:(id)dataSource {
    
    // 检查文件夹是否存在
    [self checkFolderIsExistsWithFilePath:nil];
    // 拼接缓存路径
    NSString *cachesPath = [NSString stringWithFormat:@"%@/%@.json", YWCachePath, fileName];
    NSError *error;
    NSData *data = [NSJSONSerialization dataWithJSONObject:dataSource options:NSJSONWritingPrettyPrinted error:&error];
    BOOL isTureWrite = [data writeToFile:cachesPath atomically:YES];
    if (isTureWrite) {
        YWLog(@"数据写入成功,缓存路径:%@", cachesPath);
        return YES;
    }
    YWLog(@"数据写入失败,错误消息:%@,%@", fileName, error);
    return NO;
}

// 普通json缓存 - 读取缓存
+ (nullable id)getCacheWithFileName:(NSString *)fileName {
    
    // 检查文件夹是否存在
    [self checkFolderIsExistsWithFilePath:nil];
    // 拼接缓存路径
    NSString *cachesPath = [NSString stringWithFormat:@"%@/%@.json", YWCachePath, fileName];
    NSData *data = [NSData dataWithContentsOfFile:cachesPath];
    if (data) {
        NSError *error;
        id dataSource = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:&error];
        if (!error) {
            return dataSource;
        }
        YWLog(@"数据读取失败,错误消息:%@,%@", fileName, error);
    }
    YWLog(@"暂无缓存数据");
    return nil;
    
}

#pragma mark - * * * * * 网页缓存 * * * * *
// 网页缓存写入文件
+ (BOOL)writeToHTMLCache:(NSString *)urlString {
    
    // 检查文件夹是否存在
    [self checkFolderIsExistsWithFilePath:nil];
    // 拼接缓存路径
    NSString *cachesPath = [NSString stringWithFormat:@"%@/%lu.html", YWCachePath, (unsigned long)[urlString hash]];
    // URL编码
    NSString * htmlResponseStr = [NSString stringWithContentsOfURL:[NSURL URLWithString:urlString] encoding:NSUTF8StringEncoding error:Nil];
    // 将文件写入缓存
    NSError *error;
    BOOL isTureWrite = [htmlResponseStr writeToFile:cachesPath atomically:YES encoding:NSUTF8StringEncoding error:&error];
    if (isTureWrite) {
        YWLog(@"网页数据写入成功,缓存路径:%@", cachesPath);
        return YES;
    }
    YWLog(@"网页数据写入失败,错误消息:%@,%@", urlString, error);
    return NO;
}
// 读取网页缓存
+ (NSString *)getHTMLCacheWithUrlString:(NSString *)urlString {
    
    // 检查文件夹是否存在
    [self checkFolderIsExistsWithFilePath:nil];
    // 拼接缓存路径
    NSString *cachesPath = [NSString stringWithFormat:@"%@/%lu.html", YWCachePath, (unsigned long)[urlString hash]];
    // 读取缓存文件
    NSError *error;
    NSString *htmlStr = [NSString stringWithContentsOfFile:cachesPath encoding:NSUTF8StringEncoding error:nil];
    if (!error) {
         return htmlStr;
    }
    YWLog(@"网页数据读取失败,错误消息:%@,%@", urlString, error);
    return nil;
}

#pragma mark - * * * * * 网络图片缓存 * * * * *
+ (void)writeImageToLocalCache:(NSString *)urlString successBlock:(void (^)(UIImage *image))successBlock errorBlock:(void (^)(void))errorBlock {
    
    if (!urlString && errorBlock) {
        errorBlock();
    }
    
    dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0 ), ^(void) {
        
        NSData *data = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:urlString]];
        UIImage *image = [[UIImage alloc] initWithData:data];
        dispatch_async( dispatch_get_main_queue(), ^(void){
            if(image && successBlock) {
                
                NSString *imageFilePath = [NSString stringWithFormat:@"%@/%@.jpg", YWCachePath, [urlString qmui_md5]];
                //写入本地文件
                if ([UIImageJPEGRepresentation(image, 1.0f) writeToFile:imageFilePath atomically:YES]) {
                    successBlock(image);
                }
            }else {
                if (errorBlock) errorBlock();
            }
        });
    });
}

// 读取缓存图片
+ (UIImage *)getImageWithImageUrl:(NSString *)urlString {
    if (!urlString) {
        YWLog(@"暂无缓存数据");
        return nil;
    }
    // 拼接缓存路径
    NSString *cachesPath = [NSString stringWithFormat:@"%@/%@.jpg", YWCachePath, [urlString qmui_md5]];
    NSData *data = [NSData dataWithContentsOfFile:cachesPath];
    if (data) {
        UIImage *image = [[UIImage alloc] initWithData:data];
        if (image) {
            return image;
        }
    }
    YWLog(@"暂无缓存数据");
    return nil;
}

#pragma mark - 获取path路径下文件夹大小
+ (NSString *)getCacheSizeWithFilePath:(NSString *)path {
    
    // 如果传入的路径为空,则直接统计 默认路径:YWCachePath 的缓存
    if (!path || [path isEqualToString:@""]) {
        path = YWCachePath;
    }
    // 获取“path”文件夹下的所有文件
    NSArray *subPathArr = [[NSFileManager defaultManager] subpathsAtPath:path];
    
    NSString *filePath  = nil;
    NSInteger totleSize = 0;
    
    for (NSString *subPath in subPathArr){
        // 1. 拼接每一个文件的全路径
        filePath =[path stringByAppendingPathComponent:subPath];
        // 2. 是否是文件夹,默认不是
        BOOL isDirectory = NO;
        // 3. 判断文件是否存在
        BOOL isExist = [[NSFileManager defaultManager] fileExistsAtPath:filePath isDirectory:&isDirectory];
        
        // 4. 以上判断目的是忽略不需要计算的文件
        if (!isExist || isDirectory || [filePath containsString:@".DS"]){
            // 过滤: 1. 文件夹不存在  2. 过滤文件夹  3. 隐藏文件
            continue;
        }
        // 5. 指定路径,获取这个路径的属性
        NSDictionary *dict = [[NSFileManager defaultManager] attributesOfItemAtPath:filePath error:nil];
        /**
         attributesOfItemAtPath: 文件夹路径
         该方法只能获取文件的属性, 无法获取文件夹属性, 所以也是需要遍历文件夹的每一个文件的原因
         */
        
        // 6. 获取每一个文件的大小
        NSInteger size = [dict[@"NSFileSize"] integerValue];
        
        // 7. 计算总大小
        totleSize += size;
    }
    
    //8. 将文件夹大小转换为 M/KB/B
    NSString *totleStr = totleSize ? [self getBytesFromDataLength:totleSize] : @"0.00MB";
    
    return totleStr;
}


#pragma mark - 清除path文件夹下缓存大小
+ (BOOL)clearCacheWithFilePath:(NSString *)path{
    
    // 如果传入的路径为空,则直接清除 默认路径:YWCachePath 的缓存
    if (!path || [path isEqualToString:@""]) {
        path = YWCachePath;
    }
    
    //拿到path路径的下一级目录的子文件夹
    NSArray *subPathArr = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:path error:nil];
    
    NSString *filePath = nil;
    NSError *error = nil;
    
    if (!subPathArr) {
        // 直接清理指定路径下的文件
         [[NSFileManager defaultManager] removeItemAtPath:path error:&error];
    }else {
        for (NSString *subPath in subPathArr) {
            filePath = [path stringByAppendingPathComponent:subPath];
            if (![filePath containsString:@"/Caches/Snapshots"]) {
                //删除子文件
                [[NSFileManager defaultManager] removeItemAtPath:filePath error:&error];
            }
        }
    }
    
    if (!error) {
        YWLog(@"缓存清除成功");
        return YES;
    }
    YWLog(@"缓存清除失败,错误信息:%@",error);
    return NO;
}


+ (NSString *)getBytesFromDataLength:(NSInteger)dataLength {
    NSString *bytes;
    
    if (dataLength >= 0.5 * (1024 * 1024 * 1024)) {
        bytes = [NSString stringWithFormat:@"%0.2fGB",dataLength/1024/1024.0/1024.0];
    } else if (dataLength >= 0.5 * (1024 * 1024)) {
        bytes = [NSString stringWithFormat:@"%0.2fMB",dataLength/1024/1024.0];
    } else if (dataLength >= 1024) {
        bytes = [NSString stringWithFormat:@"%0.2fKB",dataLength/1024.0];
    } else {
        bytes = [NSString stringWithFormat:@"%zdB",dataLength];
    }
    return bytes;
}


#pragma mark - * * * * * private * * * * *
// 检查文件夹是否存在
+ (BOOL)checkFolderIsExistsWithFilePath:(NSString *)path {
    
    // 如果传入的路径为空,则直接清除 默认路径:YWCachePath 的缓存
    if (!path || [path isEqualToString:@""]) {
        path = YWCachePath;
    }
    // 创建一个文件管理器
    NSFileManager *manager = [NSFileManager defaultManager];
    // 检查文件夹是否存在
    BOOL isExists = [manager fileExistsAtPath:path];
    if (!isExists) {
        // 创建文件夹
        return [manager createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:nil];
    }
    return YES;
}

@end

推荐阅读更多精彩内容

  • iOS开发系列--网络开发 概览 大部分应用程序都或多或少会牵扯到网络开发,例如说新浪微博、微信等,这些应用本身可...
    lichengjin阅读 1,535评论 0 5
  • Swift1> Swift和OC的区别1.1> Swift没有地址/指针的概念1.2> 泛型1.3> 类型严谨 对...
    cosWriter阅读 3,237评论 0 12
  • 第一部分 HTML&CSS整理答案 1. 什么是HTML5? 答:HTML5是最新的HTML标准。 注意:讲述HT...
    kismetajun阅读 8,172评论 0 31
  • https://mp.weixin.qq.com/s/cXDsvaiZo3tcJ6Bq6VzMUQ
    LIFICHAIN生命链159阅读 139评论 0 0
  • 生活其实很艰辛, 再没心没肺的人都能感觉的到。 那一个说过喜欢我的女孩, 那一个借我日记的女孩, 那一个穿我校服的...
    蓦雨清尘阅读 16评论 0 0