QNFile.m 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. //
  2. // QNFile.m
  3. // QiniuSDK
  4. //
  5. // Created by bailong on 15/7/25.
  6. // Copyright (c) 2015年 Qiniu. All rights reserved.
  7. //
  8. #import "QNFile.h"
  9. #import "QNResponseInfo.h"
  10. @interface QNFile ()
  11. @property (nonatomic, readonly) NSString *filepath;
  12. @property (nonatomic) NSData *data;
  13. @property (readonly) int64_t fileSize;
  14. @property (readonly) int64_t fileModifyTime;
  15. @property (nonatomic) NSFileHandle *file;
  16. @property (nonatomic) NSLock *lock;
  17. @end
  18. @implementation QNFile
  19. - (instancetype)init:(NSString *)path
  20. error:(NSError *__autoreleasing *)error {
  21. if (self = [super init]) {
  22. _filepath = path;
  23. NSError *error2 = nil;
  24. NSDictionary *fileAttr = [[NSFileManager defaultManager] attributesOfItemAtPath:path error:&error2];
  25. if (error2 != nil) {
  26. if (error != nil) {
  27. *error = error2;
  28. }
  29. return self;
  30. }
  31. _fileSize = [fileAttr fileSize];
  32. NSDate *modifyTime = fileAttr[NSFileModificationDate];
  33. int64_t t = 0;
  34. if (modifyTime != nil) {
  35. t = [modifyTime timeIntervalSince1970];
  36. }
  37. _fileModifyTime = t;
  38. NSFileHandle *f = nil;
  39. NSData *d = nil;
  40. //[NSData dataWithContentsOfFile:filePath options:NSDataReadingMappedIfSafe error:&error] 不能用在大于 200M的文件上,改用filehandle
  41. // 参见 https://issues.apache.org/jira/browse/CB-5790
  42. if (_fileSize > 16 * 1024 * 1024) {
  43. f = [NSFileHandle fileHandleForReadingAtPath:path];
  44. if (f == nil) {
  45. if (error != nil) {
  46. *error = [[NSError alloc] initWithDomain:path code:kQNFileError userInfo:nil];
  47. }
  48. return self;
  49. }
  50. } else {
  51. d = [NSData dataWithContentsOfFile:path options:NSDataReadingMappedIfSafe error:&error2];
  52. if (error2 != nil) {
  53. if (error != nil) {
  54. *error = error2;
  55. }
  56. return self;
  57. }
  58. }
  59. _file = f;
  60. _data = d;
  61. _lock = [[NSLock alloc] init];
  62. }
  63. return self;
  64. }
  65. - (NSData *)read:(long)offset
  66. size:(long)size
  67. error:(NSError **)error {
  68. NSData *data = nil;
  69. @try {
  70. [_lock lock];
  71. if (_data != nil) {
  72. data = [_data subdataWithRange:NSMakeRange(offset, (unsigned int)size)];
  73. } else {
  74. [_file seekToFileOffset:offset];
  75. data = [_file readDataOfLength:size];
  76. }
  77. } @catch (NSException *exception) {
  78. *error = [NSError errorWithDomain:NSCocoaErrorDomain code:kQNFileError userInfo:@{NSLocalizedDescriptionKey : exception.reason}];
  79. NSLog(@"read file failed reason: %@ \n%@", exception.reason, exception.callStackSymbols);
  80. } @finally {
  81. [_lock unlock];
  82. }
  83. return data;
  84. }
  85. - (NSData *)readAllWithError:(NSError **)error {
  86. return [self read:0 size:(long)_fileSize error:error];
  87. }
  88. - (void)close {
  89. if (_file != nil) {
  90. [_file closeFile];
  91. }
  92. }
  93. - (NSString *)path {
  94. return _filepath;
  95. }
  96. - (int64_t)modifyTime {
  97. return _fileModifyTime;
  98. }
  99. - (int64_t)size {
  100. return _fileSize;
  101. }
  102. @end