先把需求发一下:
• 客户端以日志的形式,记录用户的基本信息、使用环境、使用行为等数据。
上报策略
• 程序进入后台模式时,立即上传缓存的日志文件
• 按照时间,以每小时的频率进行数据上报
• 日志文件小于30KB时,不进行上报
• 上报成功后,清除已上传成功的日志文件
• 特殊上报策略——客户端启动触发的事件,实时上报
这里只介绍怎么对文件进行操作。
- 因为全局任何时刻都有可能会写入日志,并且有可能会存储好几个用户的日志。所以我用了单例写,并且有个属性记录下了当前操作的文件路径。那么先来写个单例。
@property (nonatomic,strong)NSString * filePath;//当前操作的文件的路径
@property (nonatomic,strong)dispatch_queue_t concurrentWriteFileQueue;//自己创建的一个线程
- (instancetype) shareInstance{
static dispatch_once_t onceToken;
static UserInfoCollection *UIC = nil;
//确保创建单例只被执行一次。
dispatch_once(&onceToken, ^{
UIC = [UserInfoCollection new];
//自己建立一个线程
UIC.concurrentWriteFileQueue = dispatch_queue_create("人家是写文件的线程自定义队列", DISPATCH_QUEUE_CONCURRENT);
});
return UIC;
}
- 创建文件。
(void)createFileWithUID:(NSString*)UID{
// 文件存储的路径,
NSArray * paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString * documentDirectory = [paths objectAtIndex:0];
NSLog(@"%@",documentDirectory);
NSFileManager *manager = [NSFileManager defaultManager];
// 路径下的所有文件名
NSArray *filePathArr = [manager contentsOfDirectoryAtPath:[NSString stringWithFormat:@"%@/",documentDirectory] error:nil];
NSLog(@"arr = %@",filePathArr);
// 用UID 匹配文件 如果已经有了某个用户的日志,那么就返回这个用户的文件路径,不创建新的。
for (NSString * file in filePathArr) {
if ([file rangeOfString:[NSString stringWithFormat:@"%@_",UID]].location != NSNotFound) {
// 已经有了文件,
//UIC.filePath 当前操作的文件的路径
UIC.filePath = [NSString stringWithFormat:@"%@/%@",documentDirectory,file];
return;
}
}
//首次创建文件名
NSString *testPath = [NSString stringWithFormat:@"%@/%@_%@_%@%@",documentDirectory,UID,@"设备号",@"时间戳",@".txt"];
BOOL ifFileExist = [manager fileExistsAtPath:testPath];
BOOL success = NO;
if (ifFileExist) {
NSLog(@"文件已经存在");
UIC.filePath = testPath;
}else{
NSLog(@"文件不存在");
success = [manager createFileAtPath:testPath contents:nil attributes:nil];
}
if (!success) {
NSLog(@"创建文件不成功");
UIC.filePath = nil;
// 错误判断+++
}else{
NSLog(@"创建文件成功");
UIC.filePath = testPath;
}
}
- 文件写入
- (void)writeMessageToFileWithJsonStr:(NSDictionary*)dic{
if (!UIC.filePath) {
NSLog(@"文件路径错误,写不进去");
return;
}
NSFileHandle *file = [NSFileHandle fileHandleForUpdatingAtPath:UIC.filePath];
// 字典转JSON
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dic options:NSJSONWritingPrettyPrinted error:nil];
NSString *json = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
NSString *jsonStr = [json stringByAppendingString:@",\n"];
// 在文件的末尾添加内容。如果想在开始写 [file seekToFileOffset:0];
[file seekToEndOfFile];
NSData *strData = [jsonStr dataUsingEncoding:NSUTF8StringEncoding];
[file writeData:strData ];
}
- 计算文件的大小
//文件大小
- (float)fileSize{
NSFileManager *manager = [NSFileManager defaultManager];
return [[manager attributesOfItemAtPath:UIC.filePath error:nil] fileSize]/(1024.0);//这里返回的单位是KB
}
- 删除文件
- (void)deleteUserInfoFile{
dispatch_barrier_async(UIC.concurrentWriteFileQueue, ^{
NSFileManager *manager = [NSFileManager defaultManager];
BOOL deleSuccess = [manager removeItemAtPath:UIC.filePath error:nil];
if (deleSuccess) {
NSLog(@"删除文件成功");
}else{
NSLog(@"删除文件不成功");
}
});
}
- 创建文件并写入一些信息
- (void)userInfoWithUID:(NSString*)UID{
//添加写操作到自定义队列,当稍后执行时,这将是队列中唯一执行的条目。这个Block永远不会同时和其他Block一起在队列中执行
dispatch_barrier_async(UIC.concurrentWriteFileQueue, ^{
[UIC createFileWithUID:UID];
NSDictionary *dic = @{
@"u":@{
@"uid":UID,//
@"device":@"设备号",
@"brand":@"设备信息",
@"os":@"设备操作系统信息",
@"tag":@"客户端发布渠道",
@"clienttype":@"iPhone",
@"version":@"x.x.xxxx"
}
};
[self writeMessageToFileWithJsonStr:dic];
});
}
自定义一个线程队列,比较方便调试 。
最后是写好的文件。