QNUploadSourceStream.m 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. //
  2. // QNUploadSourceStream.m
  3. // QiniuSDK
  4. //
  5. // Created by yangsen on 2021/5/10.
  6. // Copyright © 2021 Qiniu. All rights reserved.
  7. //
  8. #import "QNErrorCode.h"
  9. #import "QNUploadSourceStream.h"
  10. @interface QNUploadSourceStream()
  11. @property(nonatomic, assign)BOOL hasSize;
  12. @property(nonatomic, assign)long long size;
  13. @property(nonatomic, assign)long long readOffset;
  14. @property(nonatomic, copy)NSString *sourceId;
  15. @property(nonatomic, copy)NSString *fileName;
  16. @property(nonatomic, strong)NSInputStream *stream;
  17. @end
  18. @implementation QNUploadSourceStream
  19. + (instancetype)stream:(NSInputStream * _Nonnull)stream
  20. sourceId:(NSString * _Nullable)sourceId
  21. size:(long long)size
  22. fileName:(NSString * _Nullable)fileName {
  23. QNUploadSourceStream *sourceStream = [[QNUploadSourceStream alloc] init];
  24. sourceStream.stream = stream;
  25. sourceStream.sourceId = sourceId;
  26. sourceStream.fileName = fileName;
  27. sourceStream.size = size;
  28. sourceStream.hasSize = size > 0;
  29. sourceStream.readOffset = 0;
  30. return sourceStream;
  31. }
  32. - (NSString *)getId {
  33. return self.sourceId;
  34. }
  35. - (BOOL)couldReloadSource {
  36. return false;
  37. }
  38. - (BOOL)reloadSource {
  39. return false;
  40. }
  41. - (NSString *)getFileName {
  42. return self.fileName;
  43. }
  44. - (long long)getSize {
  45. if (self.size > kQNUnknownSourceSize) {
  46. return self.size;
  47. } else {
  48. return kQNUnknownSourceSize;
  49. }
  50. }
  51. - (NSData *)readData:(NSInteger)dataSize dataOffset:(long long)dataOffset error:(NSError **)error {
  52. if (self.stream == nil) {
  53. *error = [NSError errorWithDomain:NSCocoaErrorDomain code:kQNFileError userInfo:@{NSLocalizedDescriptionKey : @"inputStream is empty"}];
  54. return nil;
  55. }
  56. if (dataOffset < self.readOffset) {
  57. *error = [NSError errorWithDomain:NSCocoaErrorDomain code:kQNFileError userInfo:@{NSLocalizedDescriptionKey : @"read data error: error data offset"}];
  58. return nil;
  59. }
  60. // 打开流
  61. [self openStreamIfNeeded];
  62. if (dataOffset > self.readOffset) {
  63. // 跳过多余的数据
  64. [self streamSkipSize:dataOffset - self.readOffset error:error];
  65. if (*error != nil) {
  66. return nil;
  67. }
  68. self.readOffset = dataOffset;
  69. }
  70. // 读取数据
  71. BOOL isEOF = false;
  72. NSInteger sliceSize = 1024;
  73. NSInteger readSize = 0;
  74. NSMutableData *data = [NSMutableData data];
  75. while (readSize < dataSize) {
  76. @autoreleasepool {
  77. NSData *sliceData = [self readDataFromStream:sliceSize error:error];
  78. if (*error != nil) {
  79. break;
  80. }
  81. if (sliceData.length > 0) {
  82. readSize += sliceData.length;
  83. [data appendData:sliceData];
  84. }
  85. if (sliceData.length < sliceSize) {
  86. isEOF = true;
  87. break;
  88. }
  89. }
  90. }
  91. self.readOffset += readSize;
  92. if (*error != nil) {
  93. return nil;
  94. }
  95. if (isEOF) {
  96. self.size = self.readOffset;
  97. }
  98. return data;
  99. }
  100. - (void)openStreamIfNeeded {
  101. BOOL isOpening = true;
  102. while (true) {
  103. switch (self.stream.streamStatus) {
  104. case NSStreamStatusNotOpen:
  105. [self.stream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
  106. [self.stream open];
  107. continue;
  108. case NSStreamStatusOpening:
  109. continue;
  110. default:
  111. isOpening = false;
  112. break;
  113. }
  114. if (!isOpening) {
  115. break;
  116. }
  117. }
  118. }
  119. - (void)streamSkipSize:(long long)size error:(NSError **)error {
  120. BOOL isEOF = false;
  121. NSInteger sliceSize = 1024;
  122. NSInteger readSize = 0;
  123. while (readSize < size) {
  124. @autoreleasepool {
  125. NSData *sliceData = [self readDataFromStream:sliceSize error:error];
  126. if (*error != nil) {
  127. break;
  128. }
  129. if (sliceData.length > 0) {
  130. readSize += sliceData.length;
  131. }
  132. if (sliceData.length < sliceSize) {
  133. isEOF = true;
  134. break;
  135. }
  136. sliceData = nil;
  137. }
  138. }
  139. }
  140. // read 之前必须先 open stream
  141. - (NSData *)readDataFromStream:(NSInteger)dataSize error:(NSError **)error {
  142. BOOL isEOF = false;
  143. NSInteger readSize = 0;
  144. NSMutableData *data = [NSMutableData data];
  145. uint8_t buffer[dataSize];
  146. while (readSize < dataSize) {
  147. // 检查状态
  148. switch (self.stream.streamStatus) {
  149. case NSStreamStatusOpen:
  150. break;
  151. case NSStreamStatusReading:
  152. continue;
  153. case NSStreamStatusWriting:
  154. *error = [NSError errorWithDomain:NSCocoaErrorDomain code:kQNFileError userInfo:@{NSLocalizedDescriptionKey : @"stream is writing"}];
  155. break;
  156. case NSStreamStatusAtEnd:
  157. isEOF = true;
  158. break;
  159. case NSStreamStatusClosed:
  160. *error = [NSError errorWithDomain:NSCocoaErrorDomain code:kQNFileError userInfo:@{NSLocalizedDescriptionKey : @"stream is closed"}];
  161. break;
  162. case NSStreamStatusError:
  163. *error = self.stream.streamError;
  164. break;
  165. default:
  166. break;
  167. }
  168. if (*error != nil) {
  169. return nil;
  170. }
  171. if (isEOF) {
  172. break;
  173. }
  174. // 检查是否有数据可读
  175. if (!self.stream.hasBytesAvailable) {
  176. [NSThread sleepForTimeInterval:0.05];
  177. continue;
  178. }
  179. // 读取数据
  180. NSInteger maxLength = dataSize;
  181. NSInteger length = [self.stream read:buffer maxLength:maxLength];
  182. *error = self.stream.streamError;
  183. if (*error != nil) {
  184. return nil;
  185. }
  186. if (length > 0) {
  187. readSize += length;
  188. [data appendBytes:(const void *)buffer length:length];
  189. }
  190. }
  191. return [data copy];
  192. }
  193. - (void)close {
  194. [self.stream close];
  195. [self.stream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
  196. }
  197. - (NSString *)sourceType {
  198. return [NSString stringWithFormat:@"SourceStream:%@", _hasSize?@"HasSize":@"NoSize"];
  199. }
  200. @end