123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452 |
- //
- // CWFileStreamSeparation.m
- // uploadFileDemo
- //
- // Created by hyjet on 2018/3/9.
- // Copyright © 2018年 uploadFileDemo. All rights reserved.
- //
- #import "CWFileStreamSeparation.h"
- #import "CWFileManager.h"
- #import <CommonCrypto/CommonDigest.h>
- #import "objc/runtime.h"
- #pragma mark - CWFileStreamSeparation
- #define FileHashDefaultChunkSizeForReadingData 1024*8
- @interface CWFileStreamSeparation ()
- //@property (nonatomic, copy) NSString *fileName;
- //@property (nonatomic, assign) NSUInteger fileSize;
- //@property (nonatomic, strong) NSArray<CWStreamFragment*> *streamFragments;
- @property (nonatomic, strong) NSFileHandle *readFileHandle;
- @property (nonatomic, strong) NSFileHandle *writeFileHandle;
- @property (nonatomic, assign) BOOL isReadOperation;
- //@property (nonatomic,assign)double progressRate;
- //@property (nonatomic,assign)NSInteger uploadDateSize;
- @end
- @implementation CWFileStreamSeparation
- -(NSString *)description{
- unsigned int count;
- const char *clasName = object_getClassName(self);
- NSMutableString *string = [NSMutableString stringWithFormat:@"<%s: %p>:[ \n",clasName, self];
- Class clas = NSClassFromString([NSString stringWithCString:clasName encoding:NSUTF8StringEncoding]);
- Ivar *ivars = class_copyIvarList(clas, &count);
- for (int i = 0; i < count; i++) {
- @autoreleasepool {
- Ivar ivar = ivars[i];
- const char *name = ivar_getName(ivar);
- //得到类型
- NSString *type = [NSString stringWithCString:ivar_getTypeEncoding(ivar) encoding:NSUTF8StringEncoding];
- NSString *key = [NSString stringWithCString:name encoding:NSUTF8StringEncoding];
- id value = [self valueForKey:key];
- //确保BOOL 值输出的是YES 或 NO,这里的B是我打印属性类型得到的……
- if ([type isEqualToString:@"B"]) {
- value = (value == 0 ? @"NO" : @"YES");
- }
- [string appendFormat:@"\t%@: %@\n",[self delLine:key], value];
- }
- }
- [string appendFormat:@"]"];
- return string;
- }
- //因为ivar_getName得到的是一个带有下划线的名字,去掉下划线看起来更漂亮
- -(NSString *)delLine:(NSString *)string{
- if ([string hasPrefix:@"_"]) {
- return [string substringFromIndex:1];
- }
- return string;
- }
- + (NSString *)fileKey {
-
- CFUUIDRef uuid = CFUUIDCreate(kCFAllocatorDefault);
- CFStringRef cfstring = CFUUIDCreateString(kCFAllocatorDefault, uuid);
- const char *cStr = CFStringGetCStringPtr(cfstring,CFStringGetFastestEncoding(cfstring));
- unsigned char result[16];
- CC_MD5( cStr, (unsigned int)strlen(cStr), result );
- CFRelease(uuid);
- CFRelease(cfstring);
-
- return [NSString stringWithFormat:
- @"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%08lx",
- result[0], result[1], result[2], result[3],
- result[4], result[5], result[6], result[7],
- result[8], result[9], result[10], result[11],
- result[12], result[13], result[14], result[15],
- (unsigned long)(arc4random() % NSUIntegerMax)];
- }
- + (NSString *)fileKeyMD5WithPath:(NSString*)path
- {
- return (__bridge_transfer NSString *)FileMD5HashCreateWithPath((__bridge CFStringRef)path, FileHashDefaultChunkSizeForReadingData);
- // NSString *fileName = [path lastPathComponent];
- // return [RSATool md5Encrypt:fileName];
- }
- CFStringRef FileMD5HashCreateWithPath(CFStringRef filePath,size_t chunkSizeForReadingData) {
- // Declare needed variables
- CFStringRef result = NULL;
- CFReadStreamRef readStream = NULL;
- // Get the file URL
- CFURLRef fileURL =
- CFURLCreateWithFileSystemPath(kCFAllocatorDefault,
- (CFStringRef)filePath,
- kCFURLPOSIXPathStyle,
- (Boolean)false);
- if (!fileURL) goto done;
- // Create and open the read stream
- readStream = CFReadStreamCreateWithFile(kCFAllocatorDefault,
- (CFURLRef)fileURL);
- if (!readStream) goto done;
- bool didSucceed = (bool)CFReadStreamOpen(readStream);
- if (!didSucceed) goto done;
- // Initialize the hash object
- CC_MD5_CTX hashObject;
- CC_MD5_Init(&hashObject);
- // Make sure chunkSizeForReadingData is valid
- if (!chunkSizeForReadingData) {
- chunkSizeForReadingData = FileHashDefaultChunkSizeForReadingData;
- }
- // Feed the data to the hash object
- bool hasMoreData = true;
- while (hasMoreData) {
- uint8_t buffer[chunkSizeForReadingData];
- CFIndex readBytesCount = CFReadStreamRead(readStream,(UInt8 *)buffer,(CFIndex)sizeof(buffer));
- if (readBytesCount == -1) break;
- if (readBytesCount == 0) {
- hasMoreData = false;
- continue;
- }
- CC_MD5_Update(&hashObject,(const void *)buffer,(CC_LONG)readBytesCount);
- }
- // Check if the read operation succeeded
- didSucceed = !hasMoreData;
- // Compute the hash digest
- unsigned char digest[CC_MD5_DIGEST_LENGTH];
- CC_MD5_Final(digest, &hashObject);
- // Abort if the read operation failed
- if (!didSucceed) goto done;
- // Compute the string result
- char hash[2 * sizeof(digest) + 1];
- for (size_t i = 0; i < sizeof(digest); ++i) {
- snprintf(hash + (2 * i), 3, "%02x", (int)(digest[i]));
- }
- result = CFStringCreateWithCString(kCFAllocatorDefault,(const char *)hash,kCFStringEncodingUTF8);
-
- done:
- if (readStream) {
- CFReadStreamClose(readStream);
- CFRelease(readStream);
- }
- if (fileURL) {
- CFRelease(fileURL);
- }
- return result;
- }
- - (void)encodeWithCoder:(NSCoder *)aCoder {
-
- [aCoder encodeObject:[self fileName] forKey:@"fileName"];
- [aCoder encodeObject:[self imageData] forKey:@"imageData"];
- [aCoder encodeObject:[NSNumber numberWithDouble:[self timeStamp]] forKey:@"timeStamp"];
- [aCoder encodeObject:[self uploadLocation] forKey:@"uploadLocation"];
- [aCoder encodeObject:[NSNumber numberWithUnsignedInteger:[self fileSize]] forKey:@"fileSize"];
- [aCoder encodeObject:[NSNumber numberWithInteger:[self fileStatus]] forKey:@"fileStatus"];
- [aCoder encodeObject:[self filePath] forKey:@"filePath"];
- [aCoder encodeObject:[self md5String] forKey:@"md5String"];
- [aCoder encodeObject:[self streamFragments] forKey:@"streamFragments"];
- [aCoder encodeObject:[self bizId] forKey:@"bizId"];
- [aCoder encodeObject:[NSNumber numberWithUnsignedInteger:[self uploadDateSize]] forKey:@"uploadDateSize"];
- [aCoder encodeObject:[NSNumber numberWithDouble:[self progressRate]] forKey:@"progressRate"];
- }
- - (nullable instancetype)initWithCoder:(NSCoder *)aDecoder {
- self = [super init];
- if (self != nil) {
- [self setFileName:[aDecoder decodeObjectForKey:@"fileName"]];
- [self setImageData:[aDecoder decodeObjectForKey:@"imageData"]];
- [self setTimeStamp:[[aDecoder decodeObjectForKey:@"timeStamp"] integerValue]];
- [self setUploadLocation:[aDecoder decodeObjectForKey:@"uploadLocation"]];
- [self setFileStatus:[[aDecoder decodeObjectForKey:@"fileStatus"] intValue]];
- [self setFileSize:[[aDecoder decodeObjectForKey:@"fileSize"] unsignedIntegerValue]];
- [self setFilePath:[aDecoder decodeObjectForKey:@"filePath"]];
- [self setMd5String:[aDecoder decodeObjectForKey:@"md5String"]];
- [self setStreamFragments:[aDecoder decodeObjectForKey:@"streamFragments"]];
- [self setBizId:[aDecoder decodeObjectForKey:@"bizId"]];
- [self setProgressRate:[[aDecoder decodeObjectForKey:@"progressRate"] doubleValue]];
- [self setUploadDateSize:[[aDecoder decodeObjectForKey:@"uploadDateSize"] unsignedIntegerValue]];
- }
-
- return self;
- }
- - (BOOL)getFileInfoAtPath:(NSString*)path {
-
- NSFileManager *fileMgr = [NSFileManager defaultManager];
- if (![fileMgr fileExistsAtPath:path]) {
- HLog(@"文件不存在:%@",path);
- return NO;
- }
-
- self.filePath = path;
-
- NSDictionary *attr =[fileMgr attributesOfItemAtPath:path error:nil];
- self.fileSize = attr.fileSize;
-
- self.md5String = [CWFileStreamSeparation fileKeyMD5WithPath:path];
-
- self.bizId=[[NSUUID UUID] UUIDString];
-
- self.uploadDateSize = 0;
- self.progressRate = 0.00;
- NSString *fileName = [path lastPathComponent];
- self.fileName = fileName;
-
- self.fileStatus = CWUploadStatusWaiting;
-
- return YES;
- }
- - (BOOL)getFileInfoAtPath:(NSString*)path uploadLocation:(NSString *)uploadLocation imageData:(NSData *)imageData {
-
- NSFileManager *fileMgr = [NSFileManager defaultManager];
- if (![fileMgr fileExistsAtPath:path]) {
- HLog(@"文件不存在:%@",path);
- return NO;
- }
-
- self.filePath = path;
-
- self.uploadLocation = uploadLocation;
- self.imageData = imageData;
- self.timeStamp = [[NSDate date] timeIntervalSince1970];
-
- NSDictionary *attr =[fileMgr attributesOfItemAtPath:path error:nil];
- self.fileSize = attr.fileSize;
-
- self.md5String = [CWFileStreamSeparation fileKeyMD5WithPath:path];
-
- self.bizId=[[NSUUID UUID] UUIDString];
-
- self.uploadDateSize = 0;
- self.progressRate = 0.00;
- NSString *fileName = [path lastPathComponent];
- self.fileName = fileName;
-
- self.fileStatus = CWUploadStatusWaiting;
-
- return YES;
- }
- // 若为读取文件数据,打开一个已存在的文件。
- // 若为写入文件数据,如果文件不存在,会创建的新的空文件。
- - (instancetype)initFileOperationAtPath:(NSString*)path forReadOperation:(BOOL)isReadOperation {
-
- if (self = [super init]) {
- self.isReadOperation = isReadOperation;
- if (_isReadOperation) {
- if (![self getFileInfoAtPath:path]) {
- return nil;
- }
- self.readFileHandle = [NSFileHandle fileHandleForReadingAtPath:path];
- [self cutFileForFragments];
- } else {
- NSFileManager *fileMgr = [NSFileManager defaultManager];
- if (![fileMgr fileExistsAtPath:path]) {
- [fileMgr createFileAtPath:path contents:nil attributes:nil];
- }
-
- if (![self getFileInfoAtPath:path]) {
- return nil;
- }
-
- self.writeFileHandle = [NSFileHandle fileHandleForWritingAtPath:path];
- }
- }
-
- return self;
- }
- // 若为读取文件数据,打开一个已存在的文件。
- // 若为写入文件数据,如果文件不存在,会创建的新的空文件。
- - (instancetype)initFileOperationAtPath:(NSString*)path forReadOperation:(BOOL)isReadOperation uploadLocation:(NSString *)uploadLocation imageData:(NSData *)imageData {
-
- if (self = [super init]) {
- self.isReadOperation = isReadOperation;
- if (_isReadOperation) {
- if (![self getFileInfoAtPath:path uploadLocation:uploadLocation imageData:imageData]) {
- return nil;
- }
- self.readFileHandle = [NSFileHandle fileHandleForReadingAtPath:path];
- [self cutFileForFragments];
- } else {
- NSFileManager *fileMgr = [NSFileManager defaultManager];
- if (![fileMgr fileExistsAtPath:path]) {
- [fileMgr createFileAtPath:path contents:nil attributes:nil];
- }
-
- if (![self getFileInfoAtPath:path uploadLocation:uploadLocation imageData:imageData]) {
- return nil;
- }
-
- self.writeFileHandle = [NSFileHandle fileHandleForWritingAtPath:path];
- }
- }
-
- return self;
- }
- #pragma mark - 读操作
- //切分文件片段
- - (void)cutFileForFragments {
-
- NSUInteger offset = CWStreamFragmentMaxSize;
- // 块数
- NSUInteger chunks = (_fileSize%offset==0)?(_fileSize/offset):(_fileSize/(offset) + 1);
-
- NSMutableArray<CWStreamFragment *> *fragments = [[NSMutableArray alloc] initWithCapacity:0];
- for (NSUInteger i = 0; i < chunks; i ++) {
-
- CWStreamFragment *fFragment = [[CWStreamFragment alloc] init];
- fFragment.fragmentStatus = NO;
- fFragment.fragmentId = [[self class] fileKey];
- fFragment.fragementOffset = i * offset;
-
- if (i != chunks - 1) {
- fFragment.fragmentSize = offset;
- } else {
- fFragment.fragmentSize = _fileSize - fFragment.fragementOffset;
- }
-
- [fragments addObject:fFragment];
- }
-
- self.streamFragments = fragments;
- }
- //通过分片信息读取对应的片数据
- - (NSData*)readDateOfFragment:(CWStreamFragment*)fragment {
- HLog(@"del 2024525 暂未做");
- /* hxd del 2024525 暂未做
- if (self.readFileHandle==nil) {
-
- NSDictionary *loginDict = [[UseAccountManage shareInstance] getLoginInfo];
- if ([[loginDict allKeys] containsObject:@"account"])
- {
- NSString *fileFolder = kPath_YunPan_Upload_Folder;
- NSString *fileName = [_filePath lastPathComponent];
- NSString *fileURL = [fileFolder stringByAppendingPathComponent:fileName];
- self.readFileHandle = [NSFileHandle fileHandleForReadingAtPath:fileURL];
- }else {
- HLog(@"未登录 读取缓存文件失败!");
- }
- }
- if (fragment) {
- [self seekToFileOffset:fragment.fragementOffset];
- return [_readFileHandle readDataOfLength:fragment.fragmentSize];
- }
- [self closeFile];
- */
- return nil;
- }
- - (NSData*)readDataOfLength:(NSUInteger)bytes {
- return [_readFileHandle readDataOfLength:bytes];
- }
- - (NSData*)readDataToEndOfFile {
- return [_readFileHandle readDataToEndOfFile];
- }
- #pragma mark - 写操作
- // 写入文件数据
- - (void)writeData:(NSData *)data {
- [_writeFileHandle writeData:data];
- }
- #pragma mark - common
- // 获取当前偏移量
- - (NSUInteger)offsetInFile{
- if (_isReadOperation) {
- return [_readFileHandle offsetInFile];
- }
-
- return [_writeFileHandle offsetInFile];
- }
- // 设置偏移量,仅对读取设置
- - (void)seekToFileOffset:(NSUInteger)offset {
- [_readFileHandle seekToFileOffset:offset];
- }
- // 将偏移量定位到文件的末尾
- - (NSUInteger)seekToEndOfFile{
- if (_isReadOperation) {
- return (NSUInteger)[_readFileHandle seekToEndOfFile];
- }
-
- return [_writeFileHandle seekToEndOfFile];
- }
- // 关闭文件
- - (void)closeFile {
- if (_isReadOperation) {
- [_readFileHandle closeFile];
- } else {
- [_writeFileHandle closeFile];
- }
- }
- //归档
- + (void)archerTheDictionary:(NSDictionary *)dict file:(NSString *)path{
-
- NSData *data = [NSKeyedArchiver archivedDataWithRootObject:dict];
- BOOL finish = [data writeToFile:path atomically:YES];
- if (finish) HLog(@"归档成功");
-
- }
- //解档
- + (NSMutableDictionary *)unArcherThePlist:(NSString *)path{
- NSMutableDictionary *dic = [NSKeyedUnarchiver unarchiveObjectWithFile:path];
- return dic;
- }
- @end
- @implementation CWStreamFragment
- - (void)encodeWithCoder:(NSCoder *)aCoder {
-
- [aCoder encodeObject:[self fragmentId] forKey:@"fragmentId"];
- [aCoder encodeObject:[NSNumber numberWithUnsignedInteger:[self fragmentSize]] forKey:@"fragmentSize"];
- [aCoder encodeObject:[NSNumber numberWithUnsignedInteger:[self fragementOffset]] forKey:@"fragementOffset"];
- [aCoder encodeObject:[NSNumber numberWithUnsignedInteger:[self fragmentStatus]] forKey:@"fragmentStatus"];
- }
- - (nullable instancetype)initWithCoder:(NSCoder *)aDecoder {
- self = [super init];
- if (self != nil) {
- [self setFragmentId:[aDecoder decodeObjectForKey:@"fragmentId"]];
- [self setFragmentSize:[[aDecoder decodeObjectForKey:@"fragmentSize"] unsignedIntegerValue]];
- [self setFragementOffset:[[aDecoder decodeObjectForKey:@"fragementOffset"] unsignedIntegerValue]];
- [self setFragmentStatus:[[aDecoder decodeObjectForKey:@"fragmentStatus"] boolValue]];
- }
-
- return self;
- }
- @end
|