├── README.md └── uploadFileDemo ├── uploadFileDemo.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ ├── xcshareddata │ │ └── IDEWorkspaceChecks.plist │ └── xcuserdata │ │ ├── devcheng.xcuserdatad │ │ └── UserInterfaceState.xcuserstate │ │ └── hyjet.xcuserdatad │ │ └── UserInterfaceState.xcuserstate └── xcuserdata │ ├── devcheng.xcuserdatad │ ├── xcdebugger │ │ └── Breakpoints_v2.xcbkptlist │ └── xcschemes │ │ ├── uploadFileDemo.xcscheme │ │ └── xcschememanagement.plist │ └── hyjet.xcuserdatad │ └── xcschemes │ └── xcschememanagement.plist ├── uploadFileDemo ├── AppDelegate.h ├── AppDelegate.m ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ └── Contents.json │ ├── Contents.json │ ├── start.imageset │ │ ├── Contents.json │ │ └── start.png │ ├── stop.imageset │ │ ├── Contents.json │ │ └── stop.png │ └── video_dufalt.imageset │ │ ├── Contents.json │ │ └── video_dufalt.png ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── CWUploadFile │ ├── CWFileStreamSeparation.h │ ├── CWFileStreamSeparation.m │ ├── CWFileUploadManager.h │ ├── CWFileUploadManager.m │ ├── CWUploadTask+CheckInfo.h │ ├── CWUploadTask+CheckInfo.m │ ├── CWUploadTask.h │ └── CWUploadTask.m ├── Info.plist ├── TableViewCell.h ├── TableViewCell.m ├── TableViewCell.xib ├── TableViewController.h ├── TableViewController.m ├── Tools │ ├── CWFileManager.h │ ├── CWFileManager.m │ └── PrefixHeader.pch ├── ViewController.h ├── ViewController.m └── main.m ├── uploadFileDemoTests ├── Info.plist └── uploadFileDemoTests.m └── uploadFileDemoUITests ├── Info.plist └── uploadFileDemoUITests.m /README.md: -------------------------------------------------------------------------------- 1 | # CWUploadManager 2 | 一个iOS的文件上传Demo 3 | https://www.jianshu.com/p/04425dd2099e 4 | -------------------------------------------------------------------------------- /uploadFileDemo/uploadFileDemo.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 48; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 1334BAD3204D1197002A48B5 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 1334BAD2204D1197002A48B5 /* AppDelegate.m */; }; 11 | 1334BAD6204D1197002A48B5 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 1334BAD5204D1197002A48B5 /* ViewController.m */; }; 12 | 1334BAD9204D1197002A48B5 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 1334BAD7204D1197002A48B5 /* Main.storyboard */; }; 13 | 1334BADB204D1197002A48B5 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 1334BADA204D1197002A48B5 /* Assets.xcassets */; }; 14 | 1334BADE204D1197002A48B5 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 1334BADC204D1197002A48B5 /* LaunchScreen.storyboard */; }; 15 | 1334BAE1204D1197002A48B5 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 1334BAE0204D1197002A48B5 /* main.m */; }; 16 | 1334BAEB204D1197002A48B5 /* uploadFileDemoTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 1334BAEA204D1197002A48B5 /* uploadFileDemoTests.m */; }; 17 | 1334BAF6204D1197002A48B5 /* uploadFileDemoUITests.m in Sources */ = {isa = PBXBuildFile; fileRef = 1334BAF5204D1197002A48B5 /* uploadFileDemoUITests.m */; }; 18 | 1334BB12204D16AA002A48B5 /* CWFileUploadManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1334BB0B204D16A9002A48B5 /* CWFileUploadManager.m */; }; 19 | 1334BB13204D16AA002A48B5 /* CWUploadTask.m in Sources */ = {isa = PBXBuildFile; fileRef = 1334BB0D204D16A9002A48B5 /* CWUploadTask.m */; }; 20 | 1334BB14204D16AA002A48B5 /* CWFileManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1334BB10204D16AA002A48B5 /* CWFileManager.m */; }; 21 | 1334BB18204D2316002A48B5 /* TableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 1334BB17204D2316002A48B5 /* TableViewController.m */; }; 22 | 1334BB1C204D234F002A48B5 /* TableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 1334BB1A204D234F002A48B5 /* TableViewCell.m */; }; 23 | 1334BB1D204D234F002A48B5 /* TableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 1334BB1B204D234F002A48B5 /* TableViewCell.xib */; }; 24 | 1334BB2120521480002A48B5 /* CWUploadTask+CheckInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 1334BB2020521480002A48B5 /* CWUploadTask+CheckInfo.m */; }; 25 | DDE9765C2087324B004E8717 /* CWFileStreamSeparation.m in Sources */ = {isa = PBXBuildFile; fileRef = DDE9765B2087324B004E8717 /* CWFileStreamSeparation.m */; }; 26 | /* End PBXBuildFile section */ 27 | 28 | /* Begin PBXContainerItemProxy section */ 29 | 1334BAE7204D1197002A48B5 /* PBXContainerItemProxy */ = { 30 | isa = PBXContainerItemProxy; 31 | containerPortal = 1334BAC6204D1196002A48B5 /* Project object */; 32 | proxyType = 1; 33 | remoteGlobalIDString = 1334BACD204D1196002A48B5; 34 | remoteInfo = uploadFileDemo; 35 | }; 36 | 1334BAF2204D1197002A48B5 /* PBXContainerItemProxy */ = { 37 | isa = PBXContainerItemProxy; 38 | containerPortal = 1334BAC6204D1196002A48B5 /* Project object */; 39 | proxyType = 1; 40 | remoteGlobalIDString = 1334BACD204D1196002A48B5; 41 | remoteInfo = uploadFileDemo; 42 | }; 43 | /* End PBXContainerItemProxy section */ 44 | 45 | /* Begin PBXFileReference section */ 46 | 1334BACE204D1196002A48B5 /* uploadFileDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = uploadFileDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; 47 | 1334BAD1204D1197002A48B5 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 48 | 1334BAD2204D1197002A48B5 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 49 | 1334BAD4204D1197002A48B5 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 50 | 1334BAD5204D1197002A48B5 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 51 | 1334BAD8204D1197002A48B5 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 52 | 1334BADA204D1197002A48B5 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 53 | 1334BADD204D1197002A48B5 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 54 | 1334BADF204D1197002A48B5 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 55 | 1334BAE0204D1197002A48B5 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 56 | 1334BAE6204D1197002A48B5 /* uploadFileDemoTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = uploadFileDemoTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 57 | 1334BAEA204D1197002A48B5 /* uploadFileDemoTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = uploadFileDemoTests.m; sourceTree = ""; }; 58 | 1334BAEC204D1197002A48B5 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 59 | 1334BAF1204D1197002A48B5 /* uploadFileDemoUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = uploadFileDemoUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 60 | 1334BAF5204D1197002A48B5 /* uploadFileDemoUITests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = uploadFileDemoUITests.m; sourceTree = ""; }; 61 | 1334BAF7204D1197002A48B5 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 62 | 1334BB08204D16A9002A48B5 /* CWFileStreamSeparation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CWFileStreamSeparation.h; sourceTree = ""; }; 63 | 1334BB0A204D16A9002A48B5 /* CWFileUploadManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CWFileUploadManager.h; sourceTree = ""; }; 64 | 1334BB0B204D16A9002A48B5 /* CWFileUploadManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CWFileUploadManager.m; sourceTree = ""; }; 65 | 1334BB0C204D16A9002A48B5 /* CWUploadTask.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CWUploadTask.h; sourceTree = ""; }; 66 | 1334BB0D204D16A9002A48B5 /* CWUploadTask.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CWUploadTask.m; sourceTree = ""; }; 67 | 1334BB0F204D16AA002A48B5 /* CWFileManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CWFileManager.h; sourceTree = ""; }; 68 | 1334BB10204D16AA002A48B5 /* CWFileManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CWFileManager.m; sourceTree = ""; }; 69 | 1334BB15204D1745002A48B5 /* PrefixHeader.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PrefixHeader.pch; sourceTree = ""; }; 70 | 1334BB16204D2316002A48B5 /* TableViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TableViewController.h; sourceTree = ""; }; 71 | 1334BB17204D2316002A48B5 /* TableViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TableViewController.m; sourceTree = ""; }; 72 | 1334BB19204D234F002A48B5 /* TableViewCell.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TableViewCell.h; sourceTree = ""; }; 73 | 1334BB1A204D234F002A48B5 /* TableViewCell.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TableViewCell.m; sourceTree = ""; }; 74 | 1334BB1B204D234F002A48B5 /* TableViewCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = TableViewCell.xib; sourceTree = ""; }; 75 | 1334BB1F20521480002A48B5 /* CWUploadTask+CheckInfo.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "CWUploadTask+CheckInfo.h"; sourceTree = ""; }; 76 | 1334BB2020521480002A48B5 /* CWUploadTask+CheckInfo.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "CWUploadTask+CheckInfo.m"; sourceTree = ""; }; 77 | DDE9765B2087324B004E8717 /* CWFileStreamSeparation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CWFileStreamSeparation.m; sourceTree = ""; }; 78 | /* End PBXFileReference section */ 79 | 80 | /* Begin PBXFrameworksBuildPhase section */ 81 | 1334BACB204D1196002A48B5 /* Frameworks */ = { 82 | isa = PBXFrameworksBuildPhase; 83 | buildActionMask = 2147483647; 84 | files = ( 85 | ); 86 | runOnlyForDeploymentPostprocessing = 0; 87 | }; 88 | 1334BAE3204D1197002A48B5 /* Frameworks */ = { 89 | isa = PBXFrameworksBuildPhase; 90 | buildActionMask = 2147483647; 91 | files = ( 92 | ); 93 | runOnlyForDeploymentPostprocessing = 0; 94 | }; 95 | 1334BAEE204D1197002A48B5 /* Frameworks */ = { 96 | isa = PBXFrameworksBuildPhase; 97 | buildActionMask = 2147483647; 98 | files = ( 99 | ); 100 | runOnlyForDeploymentPostprocessing = 0; 101 | }; 102 | /* End PBXFrameworksBuildPhase section */ 103 | 104 | /* Begin PBXGroup section */ 105 | 1334BAC5204D1196002A48B5 = { 106 | isa = PBXGroup; 107 | children = ( 108 | 1334BAD0204D1196002A48B5 /* uploadFileDemo */, 109 | 1334BAE9204D1197002A48B5 /* uploadFileDemoTests */, 110 | 1334BAF4204D1197002A48B5 /* uploadFileDemoUITests */, 111 | 1334BACF204D1196002A48B5 /* Products */, 112 | ); 113 | sourceTree = ""; 114 | }; 115 | 1334BACF204D1196002A48B5 /* Products */ = { 116 | isa = PBXGroup; 117 | children = ( 118 | 1334BACE204D1196002A48B5 /* uploadFileDemo.app */, 119 | 1334BAE6204D1197002A48B5 /* uploadFileDemoTests.xctest */, 120 | 1334BAF1204D1197002A48B5 /* uploadFileDemoUITests.xctest */, 121 | ); 122 | name = Products; 123 | sourceTree = ""; 124 | }; 125 | 1334BAD0204D1196002A48B5 /* uploadFileDemo */ = { 126 | isa = PBXGroup; 127 | children = ( 128 | 1334BB07204D16A9002A48B5 /* CWUploadFile */, 129 | 1334BB0E204D16AA002A48B5 /* Tools */, 130 | 1334BAD1204D1197002A48B5 /* AppDelegate.h */, 131 | 1334BAD2204D1197002A48B5 /* AppDelegate.m */, 132 | 1334BAD4204D1197002A48B5 /* ViewController.h */, 133 | 1334BAD5204D1197002A48B5 /* ViewController.m */, 134 | 1334BB16204D2316002A48B5 /* TableViewController.h */, 135 | 1334BB17204D2316002A48B5 /* TableViewController.m */, 136 | 1334BB19204D234F002A48B5 /* TableViewCell.h */, 137 | 1334BB1A204D234F002A48B5 /* TableViewCell.m */, 138 | 1334BB1B204D234F002A48B5 /* TableViewCell.xib */, 139 | 1334BAD7204D1197002A48B5 /* Main.storyboard */, 140 | 1334BADA204D1197002A48B5 /* Assets.xcassets */, 141 | 1334BADC204D1197002A48B5 /* LaunchScreen.storyboard */, 142 | 1334BADF204D1197002A48B5 /* Info.plist */, 143 | 1334BAE0204D1197002A48B5 /* main.m */, 144 | ); 145 | path = uploadFileDemo; 146 | sourceTree = ""; 147 | }; 148 | 1334BAE9204D1197002A48B5 /* uploadFileDemoTests */ = { 149 | isa = PBXGroup; 150 | children = ( 151 | 1334BAEA204D1197002A48B5 /* uploadFileDemoTests.m */, 152 | 1334BAEC204D1197002A48B5 /* Info.plist */, 153 | ); 154 | path = uploadFileDemoTests; 155 | sourceTree = ""; 156 | }; 157 | 1334BAF4204D1197002A48B5 /* uploadFileDemoUITests */ = { 158 | isa = PBXGroup; 159 | children = ( 160 | 1334BAF5204D1197002A48B5 /* uploadFileDemoUITests.m */, 161 | 1334BAF7204D1197002A48B5 /* Info.plist */, 162 | ); 163 | path = uploadFileDemoUITests; 164 | sourceTree = ""; 165 | }; 166 | 1334BB07204D16A9002A48B5 /* CWUploadFile */ = { 167 | isa = PBXGroup; 168 | children = ( 169 | 1334BB08204D16A9002A48B5 /* CWFileStreamSeparation.h */, 170 | DDE9765B2087324B004E8717 /* CWFileStreamSeparation.m */, 171 | 1334BB0A204D16A9002A48B5 /* CWFileUploadManager.h */, 172 | 1334BB0B204D16A9002A48B5 /* CWFileUploadManager.m */, 173 | 1334BB0C204D16A9002A48B5 /* CWUploadTask.h */, 174 | 1334BB0D204D16A9002A48B5 /* CWUploadTask.m */, 175 | 1334BB1F20521480002A48B5 /* CWUploadTask+CheckInfo.h */, 176 | 1334BB2020521480002A48B5 /* CWUploadTask+CheckInfo.m */, 177 | ); 178 | path = CWUploadFile; 179 | sourceTree = ""; 180 | }; 181 | 1334BB0E204D16AA002A48B5 /* Tools */ = { 182 | isa = PBXGroup; 183 | children = ( 184 | 1334BB0F204D16AA002A48B5 /* CWFileManager.h */, 185 | 1334BB10204D16AA002A48B5 /* CWFileManager.m */, 186 | 1334BB15204D1745002A48B5 /* PrefixHeader.pch */, 187 | ); 188 | path = Tools; 189 | sourceTree = ""; 190 | }; 191 | /* End PBXGroup section */ 192 | 193 | /* Begin PBXNativeTarget section */ 194 | 1334BACD204D1196002A48B5 /* uploadFileDemo */ = { 195 | isa = PBXNativeTarget; 196 | buildConfigurationList = 1334BAFA204D1197002A48B5 /* Build configuration list for PBXNativeTarget "uploadFileDemo" */; 197 | buildPhases = ( 198 | 1334BACA204D1196002A48B5 /* Sources */, 199 | 1334BACB204D1196002A48B5 /* Frameworks */, 200 | 1334BACC204D1196002A48B5 /* Resources */, 201 | ); 202 | buildRules = ( 203 | ); 204 | dependencies = ( 205 | ); 206 | name = uploadFileDemo; 207 | productName = uploadFileDemo; 208 | productReference = 1334BACE204D1196002A48B5 /* uploadFileDemo.app */; 209 | productType = "com.apple.product-type.application"; 210 | }; 211 | 1334BAE5204D1197002A48B5 /* uploadFileDemoTests */ = { 212 | isa = PBXNativeTarget; 213 | buildConfigurationList = 1334BAFD204D1197002A48B5 /* Build configuration list for PBXNativeTarget "uploadFileDemoTests" */; 214 | buildPhases = ( 215 | 1334BAE2204D1197002A48B5 /* Sources */, 216 | 1334BAE3204D1197002A48B5 /* Frameworks */, 217 | 1334BAE4204D1197002A48B5 /* Resources */, 218 | ); 219 | buildRules = ( 220 | ); 221 | dependencies = ( 222 | 1334BAE8204D1197002A48B5 /* PBXTargetDependency */, 223 | ); 224 | name = uploadFileDemoTests; 225 | productName = uploadFileDemoTests; 226 | productReference = 1334BAE6204D1197002A48B5 /* uploadFileDemoTests.xctest */; 227 | productType = "com.apple.product-type.bundle.unit-test"; 228 | }; 229 | 1334BAF0204D1197002A48B5 /* uploadFileDemoUITests */ = { 230 | isa = PBXNativeTarget; 231 | buildConfigurationList = 1334BB00204D1197002A48B5 /* Build configuration list for PBXNativeTarget "uploadFileDemoUITests" */; 232 | buildPhases = ( 233 | 1334BAED204D1197002A48B5 /* Sources */, 234 | 1334BAEE204D1197002A48B5 /* Frameworks */, 235 | 1334BAEF204D1197002A48B5 /* Resources */, 236 | ); 237 | buildRules = ( 238 | ); 239 | dependencies = ( 240 | 1334BAF3204D1197002A48B5 /* PBXTargetDependency */, 241 | ); 242 | name = uploadFileDemoUITests; 243 | productName = uploadFileDemoUITests; 244 | productReference = 1334BAF1204D1197002A48B5 /* uploadFileDemoUITests.xctest */; 245 | productType = "com.apple.product-type.bundle.ui-testing"; 246 | }; 247 | /* End PBXNativeTarget section */ 248 | 249 | /* Begin PBXProject section */ 250 | 1334BAC6204D1196002A48B5 /* Project object */ = { 251 | isa = PBXProject; 252 | attributes = { 253 | LastUpgradeCheck = 0920; 254 | ORGANIZATIONNAME = uploadFileDemo; 255 | TargetAttributes = { 256 | 1334BACD204D1196002A48B5 = { 257 | CreatedOnToolsVersion = 9.2; 258 | ProvisioningStyle = Automatic; 259 | }; 260 | 1334BAE5204D1197002A48B5 = { 261 | CreatedOnToolsVersion = 9.2; 262 | ProvisioningStyle = Automatic; 263 | TestTargetID = 1334BACD204D1196002A48B5; 264 | }; 265 | 1334BAF0204D1197002A48B5 = { 266 | CreatedOnToolsVersion = 9.2; 267 | ProvisioningStyle = Automatic; 268 | TestTargetID = 1334BACD204D1196002A48B5; 269 | }; 270 | }; 271 | }; 272 | buildConfigurationList = 1334BAC9204D1196002A48B5 /* Build configuration list for PBXProject "uploadFileDemo" */; 273 | compatibilityVersion = "Xcode 8.0"; 274 | developmentRegion = en; 275 | hasScannedForEncodings = 0; 276 | knownRegions = ( 277 | en, 278 | Base, 279 | ); 280 | mainGroup = 1334BAC5204D1196002A48B5; 281 | productRefGroup = 1334BACF204D1196002A48B5 /* Products */; 282 | projectDirPath = ""; 283 | projectRoot = ""; 284 | targets = ( 285 | 1334BACD204D1196002A48B5 /* uploadFileDemo */, 286 | 1334BAE5204D1197002A48B5 /* uploadFileDemoTests */, 287 | 1334BAF0204D1197002A48B5 /* uploadFileDemoUITests */, 288 | ); 289 | }; 290 | /* End PBXProject section */ 291 | 292 | /* Begin PBXResourcesBuildPhase section */ 293 | 1334BACC204D1196002A48B5 /* Resources */ = { 294 | isa = PBXResourcesBuildPhase; 295 | buildActionMask = 2147483647; 296 | files = ( 297 | 1334BADE204D1197002A48B5 /* LaunchScreen.storyboard in Resources */, 298 | 1334BB1D204D234F002A48B5 /* TableViewCell.xib in Resources */, 299 | 1334BADB204D1197002A48B5 /* Assets.xcassets in Resources */, 300 | 1334BAD9204D1197002A48B5 /* Main.storyboard in Resources */, 301 | ); 302 | runOnlyForDeploymentPostprocessing = 0; 303 | }; 304 | 1334BAE4204D1197002A48B5 /* Resources */ = { 305 | isa = PBXResourcesBuildPhase; 306 | buildActionMask = 2147483647; 307 | files = ( 308 | ); 309 | runOnlyForDeploymentPostprocessing = 0; 310 | }; 311 | 1334BAEF204D1197002A48B5 /* Resources */ = { 312 | isa = PBXResourcesBuildPhase; 313 | buildActionMask = 2147483647; 314 | files = ( 315 | ); 316 | runOnlyForDeploymentPostprocessing = 0; 317 | }; 318 | /* End PBXResourcesBuildPhase section */ 319 | 320 | /* Begin PBXSourcesBuildPhase section */ 321 | 1334BACA204D1196002A48B5 /* Sources */ = { 322 | isa = PBXSourcesBuildPhase; 323 | buildActionMask = 2147483647; 324 | files = ( 325 | 1334BB12204D16AA002A48B5 /* CWFileUploadManager.m in Sources */, 326 | 1334BAD6204D1197002A48B5 /* ViewController.m in Sources */, 327 | 1334BB14204D16AA002A48B5 /* CWFileManager.m in Sources */, 328 | DDE9765C2087324B004E8717 /* CWFileStreamSeparation.m in Sources */, 329 | 1334BAE1204D1197002A48B5 /* main.m in Sources */, 330 | 1334BB1C204D234F002A48B5 /* TableViewCell.m in Sources */, 331 | 1334BB13204D16AA002A48B5 /* CWUploadTask.m in Sources */, 332 | 1334BB2120521480002A48B5 /* CWUploadTask+CheckInfo.m in Sources */, 333 | 1334BAD3204D1197002A48B5 /* AppDelegate.m in Sources */, 334 | 1334BB18204D2316002A48B5 /* TableViewController.m in Sources */, 335 | ); 336 | runOnlyForDeploymentPostprocessing = 0; 337 | }; 338 | 1334BAE2204D1197002A48B5 /* Sources */ = { 339 | isa = PBXSourcesBuildPhase; 340 | buildActionMask = 2147483647; 341 | files = ( 342 | 1334BAEB204D1197002A48B5 /* uploadFileDemoTests.m in Sources */, 343 | ); 344 | runOnlyForDeploymentPostprocessing = 0; 345 | }; 346 | 1334BAED204D1197002A48B5 /* Sources */ = { 347 | isa = PBXSourcesBuildPhase; 348 | buildActionMask = 2147483647; 349 | files = ( 350 | 1334BAF6204D1197002A48B5 /* uploadFileDemoUITests.m in Sources */, 351 | ); 352 | runOnlyForDeploymentPostprocessing = 0; 353 | }; 354 | /* End PBXSourcesBuildPhase section */ 355 | 356 | /* Begin PBXTargetDependency section */ 357 | 1334BAE8204D1197002A48B5 /* PBXTargetDependency */ = { 358 | isa = PBXTargetDependency; 359 | target = 1334BACD204D1196002A48B5 /* uploadFileDemo */; 360 | targetProxy = 1334BAE7204D1197002A48B5 /* PBXContainerItemProxy */; 361 | }; 362 | 1334BAF3204D1197002A48B5 /* PBXTargetDependency */ = { 363 | isa = PBXTargetDependency; 364 | target = 1334BACD204D1196002A48B5 /* uploadFileDemo */; 365 | targetProxy = 1334BAF2204D1197002A48B5 /* PBXContainerItemProxy */; 366 | }; 367 | /* End PBXTargetDependency section */ 368 | 369 | /* Begin PBXVariantGroup section */ 370 | 1334BAD7204D1197002A48B5 /* Main.storyboard */ = { 371 | isa = PBXVariantGroup; 372 | children = ( 373 | 1334BAD8204D1197002A48B5 /* Base */, 374 | ); 375 | name = Main.storyboard; 376 | sourceTree = ""; 377 | }; 378 | 1334BADC204D1197002A48B5 /* LaunchScreen.storyboard */ = { 379 | isa = PBXVariantGroup; 380 | children = ( 381 | 1334BADD204D1197002A48B5 /* Base */, 382 | ); 383 | name = LaunchScreen.storyboard; 384 | sourceTree = ""; 385 | }; 386 | /* End PBXVariantGroup section */ 387 | 388 | /* Begin XCBuildConfiguration section */ 389 | 1334BAF8204D1197002A48B5 /* Debug */ = { 390 | isa = XCBuildConfiguration; 391 | buildSettings = { 392 | ALWAYS_SEARCH_USER_PATHS = NO; 393 | CLANG_ANALYZER_NONNULL = YES; 394 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 395 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 396 | CLANG_CXX_LIBRARY = "libc++"; 397 | CLANG_ENABLE_MODULES = YES; 398 | CLANG_ENABLE_OBJC_ARC = YES; 399 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 400 | CLANG_WARN_BOOL_CONVERSION = YES; 401 | CLANG_WARN_COMMA = YES; 402 | CLANG_WARN_CONSTANT_CONVERSION = YES; 403 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 404 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 405 | CLANG_WARN_EMPTY_BODY = YES; 406 | CLANG_WARN_ENUM_CONVERSION = YES; 407 | CLANG_WARN_INFINITE_RECURSION = YES; 408 | CLANG_WARN_INT_CONVERSION = YES; 409 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 410 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 411 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 412 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 413 | CLANG_WARN_STRICT_PROTOTYPES = YES; 414 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 415 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 416 | CLANG_WARN_UNREACHABLE_CODE = YES; 417 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 418 | CODE_SIGN_IDENTITY = "iPhone Developer"; 419 | COPY_PHASE_STRIP = NO; 420 | DEBUG_INFORMATION_FORMAT = dwarf; 421 | ENABLE_STRICT_OBJC_MSGSEND = YES; 422 | ENABLE_TESTABILITY = YES; 423 | GCC_C_LANGUAGE_STANDARD = gnu11; 424 | GCC_DYNAMIC_NO_PIC = NO; 425 | GCC_NO_COMMON_BLOCKS = YES; 426 | GCC_OPTIMIZATION_LEVEL = 0; 427 | GCC_PREPROCESSOR_DEFINITIONS = ( 428 | "DEBUG=1", 429 | "$(inherited)", 430 | ); 431 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 432 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 433 | GCC_WARN_UNDECLARED_SELECTOR = YES; 434 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 435 | GCC_WARN_UNUSED_FUNCTION = YES; 436 | GCC_WARN_UNUSED_VARIABLE = YES; 437 | IPHONEOS_DEPLOYMENT_TARGET = 11.2; 438 | MTL_ENABLE_DEBUG_INFO = YES; 439 | ONLY_ACTIVE_ARCH = YES; 440 | SDKROOT = iphoneos; 441 | }; 442 | name = Debug; 443 | }; 444 | 1334BAF9204D1197002A48B5 /* Release */ = { 445 | isa = XCBuildConfiguration; 446 | buildSettings = { 447 | ALWAYS_SEARCH_USER_PATHS = NO; 448 | CLANG_ANALYZER_NONNULL = YES; 449 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 450 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 451 | CLANG_CXX_LIBRARY = "libc++"; 452 | CLANG_ENABLE_MODULES = YES; 453 | CLANG_ENABLE_OBJC_ARC = YES; 454 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 455 | CLANG_WARN_BOOL_CONVERSION = YES; 456 | CLANG_WARN_COMMA = YES; 457 | CLANG_WARN_CONSTANT_CONVERSION = YES; 458 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 459 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 460 | CLANG_WARN_EMPTY_BODY = YES; 461 | CLANG_WARN_ENUM_CONVERSION = YES; 462 | CLANG_WARN_INFINITE_RECURSION = YES; 463 | CLANG_WARN_INT_CONVERSION = YES; 464 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 465 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 466 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 467 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 468 | CLANG_WARN_STRICT_PROTOTYPES = YES; 469 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 470 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 471 | CLANG_WARN_UNREACHABLE_CODE = YES; 472 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 473 | CODE_SIGN_IDENTITY = "iPhone Developer"; 474 | COPY_PHASE_STRIP = NO; 475 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 476 | ENABLE_NS_ASSERTIONS = NO; 477 | ENABLE_STRICT_OBJC_MSGSEND = YES; 478 | GCC_C_LANGUAGE_STANDARD = gnu11; 479 | GCC_NO_COMMON_BLOCKS = YES; 480 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 481 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 482 | GCC_WARN_UNDECLARED_SELECTOR = YES; 483 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 484 | GCC_WARN_UNUSED_FUNCTION = YES; 485 | GCC_WARN_UNUSED_VARIABLE = YES; 486 | IPHONEOS_DEPLOYMENT_TARGET = 11.2; 487 | MTL_ENABLE_DEBUG_INFO = NO; 488 | SDKROOT = iphoneos; 489 | VALIDATE_PRODUCT = YES; 490 | }; 491 | name = Release; 492 | }; 493 | 1334BAFB204D1197002A48B5 /* Debug */ = { 494 | isa = XCBuildConfiguration; 495 | buildSettings = { 496 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 497 | CODE_SIGN_STYLE = Automatic; 498 | DEVELOPMENT_TEAM = DB9KDBVDT7; 499 | GCC_PREFIX_HEADER = uploadFileDemo/Tools/PrefixHeader.pch; 500 | INFOPLIST_FILE = uploadFileDemo/Info.plist; 501 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 502 | PRODUCT_BUNDLE_IDENTIFIER = com.whxx.uploadFileDemo; 503 | PRODUCT_NAME = "$(TARGET_NAME)"; 504 | TARGETED_DEVICE_FAMILY = 1; 505 | }; 506 | name = Debug; 507 | }; 508 | 1334BAFC204D1197002A48B5 /* Release */ = { 509 | isa = XCBuildConfiguration; 510 | buildSettings = { 511 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 512 | CODE_SIGN_STYLE = Automatic; 513 | DEVELOPMENT_TEAM = DB9KDBVDT7; 514 | GCC_PREFIX_HEADER = uploadFileDemo/Tools/PrefixHeader.pch; 515 | INFOPLIST_FILE = uploadFileDemo/Info.plist; 516 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 517 | PRODUCT_BUNDLE_IDENTIFIER = com.whxx.uploadFileDemo; 518 | PRODUCT_NAME = "$(TARGET_NAME)"; 519 | TARGETED_DEVICE_FAMILY = 1; 520 | }; 521 | name = Release; 522 | }; 523 | 1334BAFE204D1197002A48B5 /* Debug */ = { 524 | isa = XCBuildConfiguration; 525 | buildSettings = { 526 | BUNDLE_LOADER = "$(TEST_HOST)"; 527 | CODE_SIGN_STYLE = Automatic; 528 | DEVELOPMENT_TEAM = DB9KDBVDT7; 529 | INFOPLIST_FILE = uploadFileDemoTests/Info.plist; 530 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 531 | PRODUCT_BUNDLE_IDENTIFIER = com.whxx.uploadFileDemoTests; 532 | PRODUCT_NAME = "$(TARGET_NAME)"; 533 | TARGETED_DEVICE_FAMILY = "1,2"; 534 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/uploadFileDemo.app/uploadFileDemo"; 535 | }; 536 | name = Debug; 537 | }; 538 | 1334BAFF204D1197002A48B5 /* Release */ = { 539 | isa = XCBuildConfiguration; 540 | buildSettings = { 541 | BUNDLE_LOADER = "$(TEST_HOST)"; 542 | CODE_SIGN_STYLE = Automatic; 543 | DEVELOPMENT_TEAM = DB9KDBVDT7; 544 | INFOPLIST_FILE = uploadFileDemoTests/Info.plist; 545 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 546 | PRODUCT_BUNDLE_IDENTIFIER = com.whxx.uploadFileDemoTests; 547 | PRODUCT_NAME = "$(TARGET_NAME)"; 548 | TARGETED_DEVICE_FAMILY = "1,2"; 549 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/uploadFileDemo.app/uploadFileDemo"; 550 | }; 551 | name = Release; 552 | }; 553 | 1334BB01204D1197002A48B5 /* Debug */ = { 554 | isa = XCBuildConfiguration; 555 | buildSettings = { 556 | CODE_SIGN_STYLE = Automatic; 557 | DEVELOPMENT_TEAM = DB9KDBVDT7; 558 | INFOPLIST_FILE = uploadFileDemoUITests/Info.plist; 559 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 560 | PRODUCT_BUNDLE_IDENTIFIER = com.whxx.uploadFileDemoUITests; 561 | PRODUCT_NAME = "$(TARGET_NAME)"; 562 | TARGETED_DEVICE_FAMILY = "1,2"; 563 | TEST_TARGET_NAME = uploadFileDemo; 564 | }; 565 | name = Debug; 566 | }; 567 | 1334BB02204D1197002A48B5 /* Release */ = { 568 | isa = XCBuildConfiguration; 569 | buildSettings = { 570 | CODE_SIGN_STYLE = Automatic; 571 | DEVELOPMENT_TEAM = DB9KDBVDT7; 572 | INFOPLIST_FILE = uploadFileDemoUITests/Info.plist; 573 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 574 | PRODUCT_BUNDLE_IDENTIFIER = com.whxx.uploadFileDemoUITests; 575 | PRODUCT_NAME = "$(TARGET_NAME)"; 576 | TARGETED_DEVICE_FAMILY = "1,2"; 577 | TEST_TARGET_NAME = uploadFileDemo; 578 | }; 579 | name = Release; 580 | }; 581 | /* End XCBuildConfiguration section */ 582 | 583 | /* Begin XCConfigurationList section */ 584 | 1334BAC9204D1196002A48B5 /* Build configuration list for PBXProject "uploadFileDemo" */ = { 585 | isa = XCConfigurationList; 586 | buildConfigurations = ( 587 | 1334BAF8204D1197002A48B5 /* Debug */, 588 | 1334BAF9204D1197002A48B5 /* Release */, 589 | ); 590 | defaultConfigurationIsVisible = 0; 591 | defaultConfigurationName = Release; 592 | }; 593 | 1334BAFA204D1197002A48B5 /* Build configuration list for PBXNativeTarget "uploadFileDemo" */ = { 594 | isa = XCConfigurationList; 595 | buildConfigurations = ( 596 | 1334BAFB204D1197002A48B5 /* Debug */, 597 | 1334BAFC204D1197002A48B5 /* Release */, 598 | ); 599 | defaultConfigurationIsVisible = 0; 600 | defaultConfigurationName = Release; 601 | }; 602 | 1334BAFD204D1197002A48B5 /* Build configuration list for PBXNativeTarget "uploadFileDemoTests" */ = { 603 | isa = XCConfigurationList; 604 | buildConfigurations = ( 605 | 1334BAFE204D1197002A48B5 /* Debug */, 606 | 1334BAFF204D1197002A48B5 /* Release */, 607 | ); 608 | defaultConfigurationIsVisible = 0; 609 | defaultConfigurationName = Release; 610 | }; 611 | 1334BB00204D1197002A48B5 /* Build configuration list for PBXNativeTarget "uploadFileDemoUITests" */ = { 612 | isa = XCConfigurationList; 613 | buildConfigurations = ( 614 | 1334BB01204D1197002A48B5 /* Debug */, 615 | 1334BB02204D1197002A48B5 /* Release */, 616 | ); 617 | defaultConfigurationIsVisible = 0; 618 | defaultConfigurationName = Release; 619 | }; 620 | /* End XCConfigurationList section */ 621 | }; 622 | rootObject = 1334BAC6204D1196002A48B5 /* Project object */; 623 | } 624 | -------------------------------------------------------------------------------- /uploadFileDemo/uploadFileDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /uploadFileDemo/uploadFileDemo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /uploadFileDemo/uploadFileDemo.xcodeproj/project.xcworkspace/xcuserdata/devcheng.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeveloperCWG/CWUploadManager/e0e88d1fee66d760388689625e8247680f82171e/uploadFileDemo/uploadFileDemo.xcodeproj/project.xcworkspace/xcuserdata/devcheng.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /uploadFileDemo/uploadFileDemo.xcodeproj/project.xcworkspace/xcuserdata/hyjet.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeveloperCWG/CWUploadManager/e0e88d1fee66d760388689625e8247680f82171e/uploadFileDemo/uploadFileDemo.xcodeproj/project.xcworkspace/xcuserdata/hyjet.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /uploadFileDemo/uploadFileDemo.xcodeproj/xcuserdata/devcheng.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /uploadFileDemo/uploadFileDemo.xcodeproj/xcuserdata/devcheng.xcuserdatad/xcschemes/uploadFileDemo.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 43 | 49 | 50 | 51 | 52 | 53 | 59 | 60 | 61 | 62 | 63 | 64 | 74 | 76 | 82 | 83 | 84 | 85 | 86 | 87 | 93 | 95 | 101 | 102 | 103 | 104 | 106 | 107 | 110 | 111 | 112 | -------------------------------------------------------------------------------- /uploadFileDemo/uploadFileDemo.xcodeproj/xcuserdata/devcheng.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | uploadFileDemo.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 1334BACD204D1196002A48B5 16 | 17 | primary 18 | 19 | 20 | 1334BAE5204D1197002A48B5 21 | 22 | primary 23 | 24 | 25 | 1334BAF0204D1197002A48B5 26 | 27 | primary 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /uploadFileDemo/uploadFileDemo.xcodeproj/xcuserdata/hyjet.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | uploadFileDemo.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 1334BACD204D1196002A48B5 16 | 17 | primary 18 | 19 | 20 | 1334BAE5204D1197002A48B5 21 | 22 | primary 23 | 24 | 25 | 1334BAF0204D1197002A48B5 26 | 27 | primary 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /uploadFileDemo/uploadFileDemo/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // uploadFileDemo 4 | // 5 | // Created by hyjet on 2018/3/5. 6 | // Copyright © 2018年 uploadFileDemo. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /uploadFileDemo/uploadFileDemo/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // uploadFileDemo 4 | // 5 | // Created by hyjet on 2018/3/5. 6 | // Copyright © 2018年 uploadFileDemo. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | #import "CWFileUploadManager.h" 11 | 12 | @interface AppDelegate () 13 | 14 | @end 15 | 16 | @implementation AppDelegate 17 | 18 | 19 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 20 | 21 | [[CWFileUploadManager shardUploadManager] config:[self setUpRequest] maxTask:3]; 22 | 23 | return YES; 24 | } 25 | 26 | - (NSMutableURLRequest *)setUpRequest{ 27 | NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"%@/upload/file",CURRENT_API]]; 28 | NSMutableURLRequest* request=[NSMutableURLRequest requestWithURL:url]; 29 | request.HTTPMethod=@"POST"; 30 | [request setValue:[NSString stringWithFormat:@"multipart/form-data; boundary=%@",@"1a2b3c"] forHTTPHeaderField:@"Content-Type"]; 31 | [request setValue:@"v1" forHTTPHeaderField:@"api_version"]; 32 | return request; 33 | } 34 | 35 | - (void)applicationWillResignActive:(UIApplication *)application { 36 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 37 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 38 | } 39 | 40 | 41 | - (void)applicationDidEnterBackground:(UIApplication *)application { 42 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 43 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 44 | } 45 | 46 | 47 | - (void)applicationWillEnterForeground:(UIApplication *)application { 48 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 49 | } 50 | 51 | 52 | - (void)applicationDidBecomeActive:(UIApplication *)application { 53 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 54 | } 55 | 56 | 57 | - (void)applicationWillTerminate:(UIApplication *)application { 58 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 59 | } 60 | 61 | 62 | @end 63 | -------------------------------------------------------------------------------- /uploadFileDemo/uploadFileDemo/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "20x20", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "20x20", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "29x29", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "29x29", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "40x40", 66 | "scale" : "1x" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "size" : "40x40", 71 | "scale" : "2x" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "size" : "76x76", 76 | "scale" : "1x" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "size" : "76x76", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "size" : "83.5x83.5", 86 | "scale" : "2x" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "size" : "1024x1024", 91 | "scale" : "1x" 92 | } 93 | ], 94 | "info" : { 95 | "version" : 1, 96 | "author" : "xcode" 97 | } 98 | } -------------------------------------------------------------------------------- /uploadFileDemo/uploadFileDemo/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /uploadFileDemo/uploadFileDemo/Assets.xcassets/start.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "start.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /uploadFileDemo/uploadFileDemo/Assets.xcassets/start.imageset/start.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeveloperCWG/CWUploadManager/e0e88d1fee66d760388689625e8247680f82171e/uploadFileDemo/uploadFileDemo/Assets.xcassets/start.imageset/start.png -------------------------------------------------------------------------------- /uploadFileDemo/uploadFileDemo/Assets.xcassets/stop.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "stop.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /uploadFileDemo/uploadFileDemo/Assets.xcassets/stop.imageset/stop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeveloperCWG/CWUploadManager/e0e88d1fee66d760388689625e8247680f82171e/uploadFileDemo/uploadFileDemo/Assets.xcassets/stop.imageset/stop.png -------------------------------------------------------------------------------- /uploadFileDemo/uploadFileDemo/Assets.xcassets/video_dufalt.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "video_dufalt.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /uploadFileDemo/uploadFileDemo/Assets.xcassets/video_dufalt.imageset/video_dufalt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeveloperCWG/CWUploadManager/e0e88d1fee66d760388689625e8247680f82171e/uploadFileDemo/uploadFileDemo/Assets.xcassets/video_dufalt.imageset/video_dufalt.png -------------------------------------------------------------------------------- /uploadFileDemo/uploadFileDemo/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /uploadFileDemo/uploadFileDemo/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 35 | 41 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | -------------------------------------------------------------------------------- /uploadFileDemo/uploadFileDemo/CWUploadFile/CWFileStreamSeparation.h: -------------------------------------------------------------------------------- 1 | // 2 | // CWFileStreamSeparation.h 3 | // uploadFileDemo 4 | // 5 | // Created by hyjet on 2018/3/9. 6 | // Copyright © 2018年 uploadFileDemo. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | typedef enum : NSUInteger { 12 | CWUploadStatusWaiting = 0,//任务队列等待 13 | CWUploadStatusUpdownloading,//上传中 14 | CWUploadStatusPaused,//暂停 15 | CWUploadStatusFinished,//上传成功 16 | CWUploadStatusFailed //上传失败 17 | } CWUploadStatus;//任务状态 18 | 19 | #define CWStreamFragmentMaxSize 1024 *512 // 500KB 20 | 21 | 22 | @class CWStreamFragment; 23 | 24 | /** 25 | * 文件流操作类 26 | */ 27 | @interface CWFileStreamSeparation : NSObject 28 | @property (nonatomic, readonly, copy) NSString *fileName;//包括文件后缀名的文件名 29 | @property (nonatomic, readonly, assign) NSUInteger fileSize;//文件大小 30 | @property (nonatomic, copy) NSString *filePath;;//文件所在的文件目录 31 | @property (nonatomic, assign)CWUploadStatus fileStatus;//文件状态 32 | @property (nonatomic, copy)NSString *md5String;//文件md5编码名称 33 | @property (nonatomic, strong) NSArray *streamFragments;//文件分片数组 34 | @property (nonatomic, copy) NSString *bizId; 35 | 36 | @property (nonatomic,readonly,assign)double progressRate;//上传进度 37 | @property (nonatomic,readonly,assign)NSInteger uploadDateSize;//已上传文件大小 38 | 39 | //若为读取文件数据,打开一个已存在的文件。 40 | //若为写入文件数据,如果文件不存在,会创建的新的空文件。(创建FileStreamer对象就可以直接使用fragments(分片数组)属性) 41 | - (instancetype)initFileOperationAtPath:(NSString*)path forReadOperation:(BOOL)isReadOperation ; 42 | 43 | //获取当前偏移量 44 | - (NSUInteger)offsetInFile; 45 | 46 | //设置偏移量, 仅对读取设置 47 | - (void)seekToFileOffset:(NSUInteger)offset; 48 | 49 | //将偏移量定位到文件的末尾 50 | - (NSUInteger)seekToEndOfFile; 51 | 52 | //关闭文件 53 | - (void)closeFile; 54 | 55 | #pragma mark - 读操作 56 | //通过分片信息读取对应的片数据 57 | - (NSData*)readDateOfFragment:(CWStreamFragment*)fragment; 58 | 59 | //从当前文件偏移量开始 60 | - (NSData*)readDataOfLength:(NSUInteger)bytes; 61 | 62 | //从当前文件偏移量开始 63 | - (NSData*)readDataToEndOfFile; 64 | 65 | #pragma mark - 写操作 66 | //写入文件数据 67 | - (void)writeData:(NSData *)data; 68 | 69 | +(NSString*)fileKeyMD5WithPath:(NSString*)path; 70 | 71 | @end 72 | 73 | //上传文件片 74 | @interface CWStreamFragment : NSObject 75 | @property (nonatomic,copy)NSString *fragmentId; //片的唯一标识 76 | @property (nonatomic,assign)NSUInteger fragmentSize; //片的大小 77 | @property (nonatomic,assign)NSUInteger fragementOffset;//片的偏移量 78 | @property (nonatomic,assign)BOOL fragmentStatus; //上传状态 YES上传成功 79 | @end 80 | -------------------------------------------------------------------------------- /uploadFileDemo/uploadFileDemo/CWUploadFile/CWFileStreamSeparation.m: -------------------------------------------------------------------------------- 1 | // 2 | // CWFileStreamSeparation.m 3 | // uploadFileDemo 4 | // 5 | // Created by hyjet on 2018/3/9. 6 | // Copyright © 2018年 uploadFileDemo. All rights reserved. 7 | // 8 | 9 | #import "CWFileStreamSeparation.h" 10 | #import "CWFileManager.h" 11 | #import 12 | 13 | #pragma mark - CWFileStreamSeparation 14 | #define FileHashDefaultChunkSizeForReadingData 1024*8 15 | 16 | @interface CWFileStreamSeparation () 17 | @property (nonatomic, copy) NSString *fileName; 18 | @property (nonatomic, assign) NSUInteger fileSize; 19 | //@property (nonatomic, strong) NSArray *streamFragments; 20 | @property (nonatomic, strong) NSFileHandle *readFileHandle; 21 | @property (nonatomic, strong) NSFileHandle *writeFileHandle; 22 | @property (nonatomic, assign) BOOL isReadOperation; 23 | @property (nonatomic,assign)double progressRate; 24 | @property (nonatomic,assign)NSInteger uploadDateSize; 25 | @end 26 | 27 | @implementation CWFileStreamSeparation 28 | 29 | + (NSString *)fileKey { 30 | 31 | CFUUIDRef uuid = CFUUIDCreate(kCFAllocatorDefault); 32 | CFStringRef cfstring = CFUUIDCreateString(kCFAllocatorDefault, uuid); 33 | const char *cStr = CFStringGetCStringPtr(cfstring,CFStringGetFastestEncoding(cfstring)); 34 | unsigned char result[16]; 35 | CC_MD5( cStr, (unsigned int)strlen(cStr), result ); 36 | CFRelease(uuid); 37 | CFRelease(cfstring); 38 | 39 | return [NSString stringWithFormat: 40 | @"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%08lx", 41 | result[0], result[1], result[2], result[3], 42 | result[4], result[5], result[6], result[7], 43 | result[8], result[9], result[10], result[11], 44 | result[12], result[13], result[14], result[15], 45 | (unsigned long)(arc4random() % NSUIntegerMax)]; 46 | } 47 | 48 | +(NSString*)fileKeyMD5WithPath:(NSString*)path 49 | { 50 | return (__bridge_transfer NSString *)FileMD5HashCreateWithPath((__bridge CFStringRef)path, FileHashDefaultChunkSizeForReadingData); 51 | } 52 | 53 | CFStringRef FileMD5HashCreateWithPath(CFStringRef filePath,size_t chunkSizeForReadingData) { 54 | // Declare needed variables 55 | CFStringRef result = NULL; 56 | CFReadStreamRef readStream = NULL; 57 | // Get the file URL 58 | CFURLRef fileURL = 59 | CFURLCreateWithFileSystemPath(kCFAllocatorDefault, 60 | (CFStringRef)filePath, 61 | kCFURLPOSIXPathStyle, 62 | (Boolean)false); 63 | if (!fileURL) goto done; 64 | // Create and open the read stream 65 | readStream = CFReadStreamCreateWithFile(kCFAllocatorDefault, 66 | (CFURLRef)fileURL); 67 | if (!readStream) goto done; 68 | bool didSucceed = (bool)CFReadStreamOpen(readStream); 69 | if (!didSucceed) goto done; 70 | // Initialize the hash object 71 | CC_MD5_CTX hashObject; 72 | CC_MD5_Init(&hashObject); 73 | // Make sure chunkSizeForReadingData is valid 74 | if (!chunkSizeForReadingData) { 75 | chunkSizeForReadingData = FileHashDefaultChunkSizeForReadingData; 76 | } 77 | // Feed the data to the hash object 78 | bool hasMoreData = true; 79 | while (hasMoreData) { 80 | uint8_t buffer[chunkSizeForReadingData]; 81 | CFIndex readBytesCount = CFReadStreamRead(readStream,(UInt8 *)buffer,(CFIndex)sizeof(buffer)); 82 | if (readBytesCount == -1) break; 83 | if (readBytesCount == 0) { 84 | hasMoreData = false; 85 | continue; 86 | } 87 | CC_MD5_Update(&hashObject,(const void *)buffer,(CC_LONG)readBytesCount); 88 | } 89 | // Check if the read operation succeeded 90 | didSucceed = !hasMoreData; 91 | // Compute the hash digest 92 | unsigned char digest[CC_MD5_DIGEST_LENGTH]; 93 | CC_MD5_Final(digest, &hashObject); 94 | // Abort if the read operation failed 95 | if (!didSucceed) goto done; 96 | // Compute the string result 97 | char hash[2 * sizeof(digest) + 1]; 98 | for (size_t i = 0; i < sizeof(digest); ++i) { 99 | snprintf(hash + (2 * i), 3, "%02x", (int)(digest[i])); 100 | } 101 | result = CFStringCreateWithCString(kCFAllocatorDefault,(const char *)hash,kCFStringEncodingUTF8); 102 | 103 | done: 104 | if (readStream) { 105 | CFReadStreamClose(readStream); 106 | CFRelease(readStream); 107 | } 108 | if (fileURL) { 109 | CFRelease(fileURL); 110 | } 111 | return result; 112 | } 113 | 114 | 115 | - (void)encodeWithCoder:(NSCoder *)aCoder { 116 | 117 | [aCoder encodeObject:[self fileName] forKey:@"fileName"]; 118 | [aCoder encodeObject:[NSNumber numberWithUnsignedInteger:[self fileSize]] forKey:@"fileSize"]; 119 | [aCoder encodeObject:[NSNumber numberWithInteger:[self fileStatus]] forKey:@"fileStatus"]; 120 | [aCoder encodeObject:[self filePath] forKey:@"filePath"]; 121 | [aCoder encodeObject:[self md5String] forKey:@"md5String"]; 122 | [aCoder encodeObject:[self streamFragments] forKey:@"streamFragments"]; 123 | [aCoder encodeObject:[self bizId] forKey:@"bizId"]; 124 | [aCoder encodeObject:[NSNumber numberWithUnsignedInteger:[self uploadDateSize]] forKey:@"uploadDateSize"]; 125 | [aCoder encodeObject:[NSNumber numberWithDouble:[self progressRate]] forKey:@"progressRate"]; 126 | } 127 | 128 | - (nullable instancetype)initWithCoder:(NSCoder *)aDecoder { 129 | self = [super init]; 130 | if (self != nil) { 131 | [self setFileName:[aDecoder decodeObjectForKey:@"fileName"]]; 132 | [self setFileStatus:[[aDecoder decodeObjectForKey:@"fileStatus"] intValue]]; 133 | [self setFileSize:[[aDecoder decodeObjectForKey:@"fileSize"] unsignedIntegerValue]]; 134 | [self setFilePath:[aDecoder decodeObjectForKey:@"filePath"]]; 135 | [self setMd5String:[aDecoder decodeObjectForKey:@"md5String"]]; 136 | [self setStreamFragments:[aDecoder decodeObjectForKey:@"streamFragments"]]; 137 | [self setBizId:[aDecoder decodeObjectForKey:@"bizId"]]; 138 | [self setProgressRate:[[aDecoder decodeObjectForKey:@"progressRate"] doubleValue]]; 139 | [self setUploadDateSize:[[aDecoder decodeObjectForKey:@"uploadDateSize"] unsignedIntegerValue]]; 140 | } 141 | 142 | return self; 143 | } 144 | 145 | -(void)setFileStatus:(CWUploadStatus)fileStatus 146 | { 147 | _fileStatus = fileStatus; 148 | for (NSInteger num = 0; num<_streamFragments.count; num++) { 149 | CWStreamFragment *ft = _streamFragments[num]; 150 | if (num ==_streamFragments.count-1) { 151 | _progressRate = (num+1.0)/_streamFragments.count; 152 | _uploadDateSize = self.fileSize; 153 | break; 154 | } 155 | if (!ft.fragmentStatus) { 156 | _progressRate = (num+1.0)/_streamFragments.count; 157 | _uploadDateSize = CWStreamFragmentMaxSize * (num+1); 158 | break; 159 | } 160 | } 161 | } 162 | 163 | - (BOOL)getFileInfoAtPath:(NSString*)path { 164 | 165 | NSFileManager *fileMgr = [NSFileManager defaultManager]; 166 | if (![fileMgr fileExistsAtPath:path]) { 167 | NSLog(@"文件不存在:%@",path); 168 | return NO; 169 | } 170 | 171 | self.filePath = path; 172 | 173 | NSDictionary *attr =[fileMgr attributesOfItemAtPath:path error:nil]; 174 | self.fileSize = attr.fileSize; 175 | 176 | self.md5String = [CWFileStreamSeparation fileKeyMD5WithPath:path]; 177 | 178 | self.bizId=[[NSUUID UUID] UUIDString]; 179 | 180 | self.uploadDateSize = 0; 181 | self.progressRate = 0.00; 182 | 183 | NSString *fileName = [path lastPathComponent]; 184 | self.fileName = fileName; 185 | 186 | self.fileStatus = CWUploadStatusWaiting; 187 | 188 | return YES; 189 | } 190 | 191 | 192 | // 若为读取文件数据,打开一个已存在的文件。 193 | // 若为写入文件数据,如果文件不存在,会创建的新的空文件。 194 | - (instancetype)initFileOperationAtPath:(NSString*)path forReadOperation:(BOOL)isReadOperation { 195 | 196 | if (self = [super init]) { 197 | self.isReadOperation = isReadOperation; 198 | if (_isReadOperation) { 199 | if (![self getFileInfoAtPath:path]) { 200 | return nil; 201 | } 202 | self.readFileHandle = [NSFileHandle fileHandleForReadingAtPath:path]; 203 | [self cutFileForFragments]; 204 | } else { 205 | NSFileManager *fileMgr = [NSFileManager defaultManager]; 206 | if (![fileMgr fileExistsAtPath:path]) { 207 | [fileMgr createFileAtPath:path contents:nil attributes:nil]; 208 | } 209 | 210 | if (![self getFileInfoAtPath:path]) { 211 | return nil; 212 | } 213 | 214 | self.writeFileHandle = [NSFileHandle fileHandleForWritingAtPath:path]; 215 | } 216 | } 217 | 218 | return self; 219 | } 220 | 221 | //- (instancetype) 222 | 223 | #pragma mark - 读操作 224 | //切分文件片段 225 | - (void)cutFileForFragments { 226 | 227 | NSUInteger offset = CWStreamFragmentMaxSize; 228 | // 块数 229 | NSUInteger chunks = (_fileSize%offset==0)?(_fileSize/offset):(_fileSize/(offset) + 1); 230 | 231 | NSMutableArray *fragments = [[NSMutableArray alloc] initWithCapacity:0]; 232 | for (NSUInteger i = 0; i < chunks; i ++) { 233 | 234 | CWStreamFragment *fFragment = [[CWStreamFragment alloc] init]; 235 | fFragment.fragmentStatus = NO; 236 | fFragment.fragmentId = [[self class] fileKey]; 237 | fFragment.fragementOffset = i * offset; 238 | 239 | if (i != chunks - 1) { 240 | fFragment.fragmentSize = offset; 241 | } else { 242 | fFragment.fragmentSize = _fileSize - fFragment.fragementOffset; 243 | } 244 | 245 | [fragments addObject:fFragment]; 246 | } 247 | 248 | self.streamFragments = fragments; 249 | } 250 | 251 | //通过分片信息读取对应的片数据 252 | - (NSData*)readDateOfFragment:(CWStreamFragment*)fragment { 253 | if (self.readFileHandle==nil) { 254 | self.readFileHandle = [NSFileHandle fileHandleForReadingAtPath:_filePath]; 255 | } 256 | 257 | if (fragment) { 258 | [self seekToFileOffset:fragment.fragementOffset]; 259 | return [_readFileHandle readDataOfLength:fragment.fragmentSize]; 260 | } 261 | [self closeFile]; 262 | return nil; 263 | } 264 | 265 | - (NSData*)readDataOfLength:(NSUInteger)bytes { 266 | return [_readFileHandle readDataOfLength:bytes]; 267 | } 268 | 269 | 270 | - (NSData*)readDataToEndOfFile { 271 | return [_readFileHandle readDataToEndOfFile]; 272 | } 273 | 274 | #pragma mark - 写操作 275 | 276 | // 写入文件数据 277 | - (void)writeData:(NSData *)data { 278 | [_writeFileHandle writeData:data]; 279 | } 280 | 281 | #pragma mark - common 282 | // 获取当前偏移量 283 | - (NSUInteger)offsetInFile{ 284 | if (_isReadOperation) { 285 | return [_readFileHandle offsetInFile]; 286 | } 287 | 288 | return [_writeFileHandle offsetInFile]; 289 | } 290 | 291 | // 设置偏移量,仅对读取设置 292 | - (void)seekToFileOffset:(NSUInteger)offset { 293 | [_readFileHandle seekToFileOffset:offset]; 294 | } 295 | 296 | // 将偏移量定位到文件的末尾 297 | - (NSUInteger)seekToEndOfFile{ 298 | if (_isReadOperation) { 299 | return (NSUInteger)[_readFileHandle seekToEndOfFile]; 300 | } 301 | 302 | return [_writeFileHandle seekToEndOfFile]; 303 | } 304 | 305 | // 关闭文件 306 | - (void)closeFile { 307 | if (_isReadOperation) { 308 | [_readFileHandle closeFile]; 309 | } else { 310 | [_writeFileHandle closeFile]; 311 | } 312 | } 313 | 314 | //归档 315 | + (void)archerTheDictionary:(NSDictionary *)dict file:(NSString *)path{ 316 | 317 | NSData *data = [NSKeyedArchiver archivedDataWithRootObject:dict]; 318 | BOOL finish = [data writeToFile:path atomically:YES]; 319 | if (finish) NSLog(@"归档成功"); 320 | 321 | } 322 | 323 | //解档 324 | + (NSMutableDictionary *)unArcherThePlist:(NSString *)path{ 325 | NSMutableDictionary *dic = [NSKeyedUnarchiver unarchiveObjectWithFile:path]; 326 | return dic; 327 | } 328 | 329 | @end 330 | 331 | 332 | 333 | 334 | @implementation CWStreamFragment 335 | 336 | - (void)encodeWithCoder:(NSCoder *)aCoder { 337 | 338 | [aCoder encodeObject:[self fragmentId] forKey:@"fragmentId"]; 339 | [aCoder encodeObject:[NSNumber numberWithUnsignedInteger:[self fragmentSize]] forKey:@"fragmentSize"]; 340 | [aCoder encodeObject:[NSNumber numberWithUnsignedInteger:[self fragementOffset]] forKey:@"fragementOffset"]; 341 | [aCoder encodeObject:[NSNumber numberWithUnsignedInteger:[self fragmentStatus]] forKey:@"fragmentStatus"]; 342 | } 343 | 344 | - (nullable instancetype)initWithCoder:(NSCoder *)aDecoder { 345 | self = [super init]; 346 | if (self != nil) { 347 | [self setFragmentId:[aDecoder decodeObjectForKey:@"fragmentId"]]; 348 | [self setFragmentSize:[[aDecoder decodeObjectForKey:@"fragmentSize"] unsignedIntegerValue]]; 349 | [self setFragementOffset:[[aDecoder decodeObjectForKey:@"fragementOffset"] unsignedIntegerValue]]; 350 | [self setFragmentStatus:[[aDecoder decodeObjectForKey:@"fragmentStatus"] boolValue]]; 351 | } 352 | 353 | return self; 354 | } 355 | 356 | @end 357 | -------------------------------------------------------------------------------- /uploadFileDemo/uploadFileDemo/CWUploadFile/CWFileUploadManager.h: -------------------------------------------------------------------------------- 1 | // 2 | // CWFileUploadManager.h 3 | // uploadFileDemo 4 | // 5 | // Created by hyjet on 2018/3/9. 6 | // Copyright © 2018年 uploadFileDemo. All rights reserved. 7 | // 8 | 9 | #import 10 | @class CWUploadTask; 11 | @class CWFileStreamSeparation; 12 | 13 | 14 | @interface CWFileUploadManager : NSObject 15 | //总的文件分片模型数 16 | @property (nonatomic,readonly)NSMutableDictionary *fileStreamDict; 17 | 18 | //总任务数 19 | @property (nonatomic,readonly)NSMutableDictionary *allTasks; 20 | 21 | //正在上传中的任务 22 | @property (nonatomic,readonly)NSMutableDictionary *uploadingTasks; 23 | 24 | //正在等待上传的任务 25 | @property (nonatomic,readonly)NSMutableDictionary *uploadWaitTasks; 26 | 27 | //已经上传完的任务 28 | @property (nonatomic,readonly)NSMutableDictionary *uploadEndTasks; 29 | 30 | //同时上传的任务数 31 | @property (nonatomic,readonly)NSInteger uploadMaxNum; 32 | 33 | //配置的上传路径 34 | @property (nonatomic,readonly)NSURL *url; 35 | 36 | //配置的请求体 37 | @property (nonatomic,readonly)NSMutableURLRequest *request; 38 | 39 | //获得管理类单例对象 40 | + (instancetype)shardUploadManager; 41 | 42 | //配置全局默认参数 43 | /** 44 | @param request 默认请求头 45 | @param num 最大任务数 46 | */ 47 | - (void)config:(NSMutableURLRequest * _Nonnull)request maxTask:(NSInteger)num; 48 | 49 | //根据文件路径创建上传任务 50 | - (CWUploadTask *_Nullable)createUploadTask:(NSString *_Nonnull)filePath; 51 | 52 | 53 | /** 54 | 暂停一个上传任务 55 | 56 | @param fileStream 上传文件的路径 57 | */ 58 | - (void)pauseUploadTask:(CWFileStreamSeparation *_Nonnull)fileStream; 59 | 60 | /** 61 | 继续开始一个上传任务 62 | 63 | @param fileStream 上传文件的路径 64 | */ 65 | - (void)resumeUploadTask:(CWFileStreamSeparation *_Nonnull)fileStream; 66 | 67 | /** 68 | 删除一个上传任务,同时会删除当前任务上传的缓存数据 69 | 70 | @param fileStream 上传文件的路径 71 | */ 72 | - (void)removeUploadTask:(CWFileStreamSeparation *_Nonnull)fileStream; 73 | 74 | /** 75 | 暂停所有上传任务 76 | */ 77 | - (void)pauseAllUploadTask; 78 | 79 | /** 80 | 删除所有上传任务 81 | */ 82 | - (void)removeAllUploadTask; 83 | 84 | 85 | @end 86 | 87 | -------------------------------------------------------------------------------- /uploadFileDemo/uploadFileDemo/CWUploadFile/CWFileUploadManager.m: -------------------------------------------------------------------------------- 1 | // 2 | // CWFileUploadManager.m 3 | // uploadFileDemo 4 | // 5 | // Created by hyjet on 2018/3/9. 6 | // Copyright © 2018年 uploadFileDemo. All rights reserved. 7 | // 8 | 9 | #import "CWFileUploadManager.h" 10 | #import "CWFileStreamSeparation.h" 11 | #import "CWUploadTask.h" 12 | #import "CWFileManager.h" 13 | 14 | #define plistPath [[CWFileManager cachesDir] stringByAppendingPathComponent:uploadPlist] 15 | #define default_max @"uploadMax" 16 | 17 | @interface CWFileUploadManager () 18 | 19 | @property (nonatomic,strong)NSMutableDictionary *fileStreamDict; 20 | 21 | @property (nonatomic,strong)NSMutableDictionary *allTasks; 22 | 23 | //正在上传中的任务 24 | @property (nonatomic,strong)NSMutableDictionary *uploadingTasks; 25 | 26 | //正在等待上传的任务 27 | @property (nonatomic,strong)NSMutableDictionary *uploadWaitTasks; 28 | 29 | //已经上传完的任务 30 | @property (nonatomic,strong)NSMutableDictionary *uploadEndTasks; 31 | 32 | @property (nonatomic,assign)NSInteger uploadMaxNum; 33 | 34 | @property (nonatomic,strong)NSURL *url; 35 | @property (nonatomic,strong)NSMutableURLRequest *request; 36 | 37 | @end 38 | 39 | @implementation CWFileUploadManager 40 | 41 | static CWFileUploadManager * _instance; 42 | 43 | -(NSMutableDictionary *)fileStreamDict{ 44 | if (!_fileStreamDict) { 45 | _fileStreamDict = [NSMutableDictionary dictionary]; 46 | } 47 | return _fileStreamDict; 48 | } 49 | 50 | - (NSMutableDictionary *)allTasks 51 | { 52 | if (!_allTasks) { 53 | _allTasks = [_instance allUploadTasks]; 54 | } 55 | return _allTasks; 56 | } 57 | 58 | - (NSMutableDictionary *)uploadingTasks 59 | { 60 | return [self allUploadingTasks]; 61 | } 62 | 63 | - (NSMutableDictionary *)uploadWaitTasks 64 | { 65 | return [self allUploadWaitTasks]; 66 | } 67 | 68 | - (NSMutableDictionary *)uploadEndTasks 69 | { 70 | return [self allUploadEndTasks]; 71 | } 72 | 73 | + (instancetype)shardUploadManager { 74 | static dispatch_once_t onceToken; 75 | dispatch_once(&onceToken, ^{ 76 | _instance = [[self alloc] init]; 77 | [_instance registeNotification]; 78 | [_instance defaultsTask]; 79 | 80 | }); 81 | return _instance; 82 | } 83 | 84 | + (CWUploadTask *)startUploadWithPath:(NSString *)path 85 | { 86 | //是否是在册任务 87 | if (![CWFileUploadManager isUploadTask:path]) { 88 | [_instance taskRecord:path]; 89 | 90 | } 91 | return [_instance continuePerformTaskWithFilePath:path]; 92 | } 93 | 94 | - (CWUploadTask *_Nullable)createUploadTask:(NSString *_Nonnull)filePath 95 | { 96 | //是否是在册任务 97 | if (![CWFileUploadManager isUploadTask:filePath]) { 98 | [_instance taskRecord:filePath]; 99 | 100 | } 101 | return [self continuePerformTaskWithFilePath:filePath]; 102 | } 103 | 104 | //配置全局默认的参数 105 | - (void)config:(NSMutableURLRequest *)request maxTask:(NSInteger)num 106 | { 107 | if (!request.URL) { 108 | NSLog(@"request缺少URL"); 109 | } 110 | [[NSUserDefaults standardUserDefaults] setInteger:num forKey:default_max]; 111 | self.uploadMaxNum = num; 112 | self.url = request.URL; 113 | self.request = request; 114 | } 115 | 116 | //设置最大任务数 117 | - (void)setUploadMaxNum:(NSInteger)uploadMaxNum 118 | { 119 | if (_uploadMaxNum<3) { 120 | _uploadMaxNum = uploadMaxNum; 121 | }else if (_uploadMaxNum<0){ 122 | _uploadMaxNum = 3; 123 | }else if(_uploadMaxNum>=3){ 124 | _uploadMaxNum = 3; 125 | } 126 | } 127 | 128 | - (void)defaultsTask{ 129 | NSInteger tmpMax = [[NSUserDefaults standardUserDefaults] integerForKey:default_max]; 130 | self.uploadMaxNum = tmpMax?tmpMax:3; 131 | } 132 | 133 | /** 134 | 暂停一个上传任务 135 | */ 136 | - (void)pauseUploadTask:(CWFileStreamSeparation *_Nonnull)fileStream 137 | { 138 | CWUploadTask *task = [self.allTasks objectForKey:fileStream.fileName]; 139 | [task taskCancel]; 140 | } 141 | 142 | /** 143 | 继续开始一个上传任务 144 | */ 145 | - (void)resumeUploadTask:(CWFileStreamSeparation *_Nonnull)fileStream 146 | { 147 | CWUploadTask *task = [self.allTasks objectForKey:fileStream.fileName]; 148 | [task taskResume]; 149 | } 150 | 151 | /** 152 | 删除一个上传任务,同时会删除当前任务上传的缓存数据 153 | */ 154 | - (void)removeUploadTask:(CWFileStreamSeparation *_Nonnull)fileStream 155 | { 156 | CWUploadTask *task = [self.allTasks objectForKey:fileStream.fileName]; 157 | 158 | [task taskCancel]; 159 | 160 | [_allTasks removeObjectForKey:fileStream.fileName]; 161 | [_uploadingTasks removeObjectForKey:fileStream.fileName]; 162 | if (_fileStreamDict[fileStream.fileName]) { 163 | _fileStreamDict = [self unArcherThePlist:plistPath]; 164 | } 165 | [_fileStreamDict removeObjectForKey:fileStream.fileName]; 166 | 167 | [self archerTheDictionary:_fileStreamDict file:plistPath]; 168 | NSLog(@"删除任务"); 169 | } 170 | 171 | /** 172 | 暂停所有的上传任务 173 | */ 174 | - (void)pauseAllUploadTask 175 | { 176 | for (CWUploadTask *task in [self.allTasks allValues]) { 177 | [task taskCancel]; 178 | } 179 | } 180 | 181 | /** 182 | 删除所有的上传任务 183 | */ 184 | - (void)removeAllUploadTask 185 | { 186 | for (CWUploadTask *task in [self.allTasks allValues]) { 187 | [self removeUploadTask:task.fileStream]; 188 | } 189 | } 190 | 191 | /** 192 | 获取所有文件分片模型的上传任务字典 193 | */ 194 | - (NSMutableDictionary*_Nullable)allUploadTasks 195 | { 196 | if (self.fileStreamDict.count == 0) { 197 | self.fileStreamDict = [self unArcherThePlist:plistPath]; 198 | } 199 | NSDictionary *tmpDict = _allTasks?_allTasks:@{}; 200 | NSMutableDictionary *fileWithTasks = [CWUploadTask uploadTasksWithDict:_instance.fileStreamDict]; 201 | 202 | [fileWithTasks addEntriesFromDictionary:tmpDict]; 203 | return fileWithTasks; 204 | } 205 | 206 | - (NSMutableDictionary*_Nullable)allUploadWaitTasks 207 | { 208 | NSMutableDictionary *dic = [NSMutableDictionary dictionary]; 209 | [self.allTasks enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) { 210 | CWUploadTask *task = obj; 211 | if (task.fileStream.fileStatus == CWUploadStatusWaiting && 212 | task.fileStream.fileStatus != CWUploadStatusFailed) { 213 | [dic setObject:task forKey:key]; 214 | } 215 | }]; 216 | return dic; 217 | } 218 | 219 | - (NSMutableDictionary*_Nullable)allUploadEndTasks 220 | { 221 | NSMutableDictionary *dic = [NSMutableDictionary dictionary]; 222 | [self.uploadingTasks enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) { 223 | CWUploadTask *task = obj; 224 | if (task.fileStream.fileStatus == CWUploadStatusFinished) { 225 | [dic setObject:task forKey:key]; 226 | } 227 | }]; 228 | return dic; 229 | } 230 | 231 | - (NSMutableDictionary*_Nullable)allUploadingTasks 232 | { 233 | NSMutableDictionary *dic = [NSMutableDictionary dictionary]; 234 | [self.allTasks enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) { 235 | CWUploadTask *task = obj; 236 | if (task.fileStream.fileStatus == CWUploadStatusUpdownloading) { 237 | [dic setObject:task forKey:key]; 238 | } 239 | }]; 240 | 241 | return dic; 242 | } 243 | 244 | #pragma 工具方法 245 | - (CWUploadTask *)continuePerformTaskWithFilePath:(NSString *)path{ 246 | 247 | //获取任务数据字段 248 | CWFileStreamSeparation *fstream = [self.fileStreamDict objectForKey:path.lastPathComponent]; 249 | CWUploadTask *uploadTask = self.allTasks[path.lastPathComponent]; 250 | if (!uploadTask) { 251 | uploadTask = [CWUploadTask initWithStreamModel:fstream]; 252 | [self.allTasks setObject:uploadTask forKey:path.lastPathComponent]; 253 | } 254 | [uploadTask taskResume]; 255 | return uploadTask; 256 | } 257 | 258 | + (BOOL)isUploadTask:(NSString *)path{ 259 | _instance = [CWFileUploadManager shardUploadManager]; 260 | if (![CWFileManager isFileAtPath:plistPath]) { 261 | [CWFileManager createFileAtPath:plistPath overwrite:NO]; 262 | } 263 | _instance.fileStreamDict = [_instance unArcherThePlist:plistPath]; 264 | if (_instance.fileStreamDict[path.lastPathComponent] == nil) { 265 | return NO; 266 | }else{ 267 | return YES; 268 | } 269 | } 270 | 271 | //新建任务分片模型并存入plist文件 272 | - (CWFileStreamSeparation * _Nullable)taskRecord:(NSString *)path{ 273 | 274 | CWFileStreamSeparation *file = [[CWFileStreamSeparation alloc]initFileOperationAtPath:path forReadOperation:YES]; 275 | [self.fileStreamDict setObject:file forKey:path.lastPathComponent]; 276 | 277 | [self archerTheDictionary:_fileStreamDict file:plistPath]; 278 | 279 | return file; 280 | } 281 | 282 | #pragma mark - notification 283 | 284 | - (void)registeNotification{ 285 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationBecomeActive) name:UIApplicationDidBecomeActiveNotification object:nil]; 286 | 287 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(taskExeEnd:) name:CWUploadTaskExeEnd object:nil]; 288 | 289 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(taskExeError:) name:CWUploadTaskExeError object:nil]; 290 | } 291 | 292 | //app启动或者app从后台进入前台都会调用这个方法 293 | - (void)applicationBecomeActive{ 294 | [self uploadingTasksItemExe]; 295 | } 296 | 297 | - (void)taskExeEnd:(NSNotification *)notification 298 | { 299 | CWFileStreamSeparation *fs = notification.userInfo.allValues.firstObject; 300 | [_uploadingTasks removeObjectForKey:fs.fileName]; 301 | [self.uploadWaitTasks enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) { 302 | CWUploadTask *task = obj; 303 | if (_uploadWaitTasks.count 10 | @class CWFileStreamSeparation; 11 | 12 | #ifdef __cplusplus 13 | #define TASK_EXTERN extern "C" __attribute__((visibility ("default"))) 14 | #else 15 | #define TASK_EXTERN extern __attribute__((visibility ("default"))) 16 | #endif 17 | 18 | /** 19 | 通知监听上传状态的key 20 | */ 21 | TASK_EXTERN NSString * _Nonnull const CWUploadTaskExeing;//上传中 22 | TASK_EXTERN NSString * _Nonnull const CWUploadTaskExeError;//上传失败 23 | TASK_EXTERN NSString * _Nonnull const CWUploadTaskExeEnd;//上传完成 24 | TASK_EXTERN NSString * _Nonnull const CWUploadTaskExeSuspend;//上传暂停/取消 25 | 26 | typedef void(^finishHandler)(CWFileStreamSeparation * _Nullable fileStream, NSError * _Nullable error); 27 | 28 | typedef void(^success)(CWFileStreamSeparation * _Nullable fileStream); 29 | 30 | @interface CWUploadTask : NSObject 31 | 32 | @property (nonatomic,readonly,strong)CWFileStreamSeparation *_Nullable fileStream; 33 | //当前上传任务的URL 34 | @property (nonatomic,readonly,strong)NSURL * _Nullable url; 35 | //当前上传任务的参数 36 | @property (nonatomic,readonly,strong)NSMutableDictionary * _Nullable param; 37 | //任务对象的执行状态 38 | @property (nonatomic,readonly,assign)NSURLSessionTaskState taskState; 39 | //上传任务的唯一ID 40 | @property (nonatomic,readonly,copy)NSString * _Nullable ID; 41 | 42 | /** 43 | 根据一个文件分片模型创建一个上传任务,执行 taskResume 方法开始上传 44 | 使用 listenTaskExeCallback 方法传递block进行回调监听 45 | 同时也可以选择实现协议方法进行回调监听 46 | */ 47 | + (instancetype _Nonnull )initWithStreamModel:(CWFileStreamSeparation * _Nonnull)fileStream; 48 | 49 | /** 50 | 监听一个已存在的上传任务的状态 51 | */ 52 | - (void)listenTaskExeCallback:(finishHandler _Nonnull)block 53 | success:(success _Nonnull)successBlock; 54 | 55 | /** 56 | 根据一个文件分片模型的字典创建一个上传任务(处于等待状态)字典 57 | */ 58 | + (NSMutableDictionary *_Nullable)uploadTasksWithDict:(NSDictionary *_Nullable)dict; 59 | 60 | /** 61 | 根据一个文件分片模型创建一个上传任务,执行 startExe 方法开始上传,结果会由block回调出来 62 | */ 63 | - (instancetype _Nonnull)initWithStreamModel:(CWFileStreamSeparation *_Nonnull)fileStream 64 | finish:(finishHandler _Nonnull)block 65 | success:(success _Nonnull)successBlock; 66 | 67 | 68 | //继续/开始上传 69 | - (void)taskResume; 70 | 71 | //取消/暂停上传 72 | - (void)taskCancel; 73 | 74 | 75 | @end 76 | -------------------------------------------------------------------------------- /uploadFileDemo/uploadFileDemo/CWUploadFile/CWUploadTask.m: -------------------------------------------------------------------------------- 1 | // 2 | // CWUploadTask.m 3 | // uploadFileDemo 4 | // 5 | // Created by hyjet on 2018/3/9. 6 | // Copyright © 2018年 uploadFileDemo. All rights reserved. 7 | // 8 | 9 | #import "CWUploadTask.h" 10 | #import "CWFileUploadManager.h" 11 | #import "CWFileStreamSeparation.h" 12 | #import "CWFileManager.h" 13 | #import "CWUploadTask+CheckInfo.h" 14 | 15 | //分隔符 16 | #define Boundary @"1a2b3c" 17 | //一般换行 18 | #define Wrap1 @"\r\n" 19 | //key-value换行 20 | #define Wrap2 @"\r\n\r\n" 21 | //开始分割 22 | #define StartBoundary [NSString stringWithFormat:@"--%@%@",Boundary,Wrap1] 23 | //文件分割完成 24 | #define EndBody [NSString stringWithFormat:@"--%@--",Boundary] 25 | //一个片段上传失败默认重试3次 26 | #define REPEAT_MAX 3 27 | 28 | #define plistPath [[CWFileManager cachesDir] stringByAppendingPathComponent:uploadPlist] 29 | 30 | NSString *const CWUploadTaskExeing = @"TaskExeing"; 31 | NSString *const CWUploadTaskExeError = @"TaskExeError"; 32 | NSString *const CWUploadTaskExeEnd = @"TaskExeEnd"; 33 | NSString *const CWUploadTaskExeSuspend = @"TaskExeSuspend"; 34 | 35 | @interface CWUploadTask () 36 | 37 | @property (nonatomic,strong)NSURLSessionUploadTask *uploadTask; 38 | 39 | @property (nonatomic,strong)NSMutableURLRequest *request; 40 | 41 | @property (nonatomic,readwrite)NSURL * url; 42 | 43 | @property (nonatomic,readwrite)NSString *ID; 44 | 45 | @property (nonatomic,readwrite)NSMutableDictionary *param;//上传时参数 46 | 47 | @property (nonatomic,readwrite)NSURLSessionTaskState taskState; 48 | 49 | @property (nonatomic,readwrite)CWFileStreamSeparation *fileStream; 50 | 51 | @property (nonatomic,copy)finishHandler finishBlock;//片段上传成功上传的回调block 52 | 53 | @property (nonatomic,copy)success successBlock;//整体上传成功上传的回调block 54 | 55 | @property (nonatomic,copy)NSString *chunkNumName;//片段编号这一参数的参数名 56 | 57 | @property (nonatomic,copy)NSDictionary *lastParam;//片段完成上传后的参数 58 | 59 | @property (nonatomic,assign)NSInteger chunkNo;//片段完成上传后的编号 60 | 61 | @property (nonatomic,assign)NSInteger taskRepeatNum;//重试次数 62 | 63 | @property (nonatomic,assign)BOOL isSuspendedState;//记录状态更改 64 | 65 | @property (nonatomic,strong)CWFileUploadManager *uploadManager; 66 | 67 | @end 68 | 69 | @implementation CWUploadTask 70 | 71 | -(CWFileUploadManager *)uploadManager 72 | { 73 | if (!_uploadManager) { 74 | _uploadManager = [CWFileUploadManager shardUploadManager]; 75 | } 76 | return _uploadManager; 77 | } 78 | 79 | - (void)setFileStream:(CWFileStreamSeparation *)fileStream 80 | { 81 | _fileStream.fileStatus = CWUploadStatusWaiting; 82 | _taskRepeatNum = 0; 83 | _ID = fileStream.md5String; 84 | for (NSInteger idx=0; idx *)uploadTasksWithDict:(NSDictionary *)dict{ 95 | NSMutableDictionary *taskDict = [NSMutableDictionary dictionary]; 96 | for (NSString *key in dict.allKeys) { 97 | CWFileStreamSeparation *fs = [dict objectForKey:key]; 98 | CWUploadTask *task = [CWUploadTask initWithStreamModel:fs]; 99 | [taskDict setValue:task forKey:key]; 100 | } 101 | return taskDict; 102 | } 103 | 104 | + (instancetype)initWithStreamModel:(CWFileStreamSeparation *)fileStream 105 | { 106 | CWUploadTask *task = [CWUploadTask new]; 107 | task.fileStream = fileStream; 108 | task.isSuspendedState = NO; 109 | task.url = [CWFileUploadManager shardUploadManager].url; 110 | return task; 111 | } 112 | 113 | - (void)listenTaskExeCallback:(finishHandler _Nonnull)block success:(success)successBlock 114 | { 115 | self.finishBlock = block; 116 | self.successBlock = successBlock; 117 | if (_finishBlock) _finishBlock(_fileStream,nil); 118 | } 119 | 120 | 121 | - (instancetype _Nonnull)initWithStreamModel:(CWFileStreamSeparation *)fileStream finish:(finishHandler _Nonnull)block success:(success)successBlock 122 | 123 | { 124 | if (self = [super init]) { 125 | self.fileStream = fileStream; 126 | _finishBlock = block; 127 | _successBlock = successBlock; 128 | } 129 | return self; 130 | } 131 | 132 | -(NSMutableURLRequest*)uploadRequest 133 | { 134 | if ([CWFileUploadManager shardUploadManager].request) { 135 | _request = [CWFileUploadManager shardUploadManager].request; 136 | }else{ 137 | NSLog(@"请配置上传任务的request"); 138 | } 139 | return _request; 140 | 141 | } 142 | 143 | -(NSData*)taskRequestBodyWithParam:(NSDictionary *)param uploadData:(NSData *)data 144 | { 145 | NSMutableData* totlData=[NSMutableData new]; 146 | 147 | NSArray* allKeys=[param allKeys]; 148 | for (int i=0; i 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | NSAppTransportSecurity 24 | 25 | NSAllowsArbitraryLoads 26 | 27 | 28 | UILaunchStoryboardName 29 | LaunchScreen 30 | UIMainStoryboardFile 31 | Main 32 | UIRequiredDeviceCapabilities 33 | 34 | armv7 35 | 36 | UISupportedInterfaceOrientations 37 | 38 | UIInterfaceOrientationPortrait 39 | UIInterfaceOrientationLandscapeLeft 40 | UIInterfaceOrientationLandscapeRight 41 | 42 | UISupportedInterfaceOrientations~ipad 43 | 44 | UIInterfaceOrientationPortrait 45 | UIInterfaceOrientationPortraitUpsideDown 46 | UIInterfaceOrientationLandscapeLeft 47 | UIInterfaceOrientationLandscapeRight 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /uploadFileDemo/uploadFileDemo/TableViewCell.h: -------------------------------------------------------------------------------- 1 | // 2 | // TableViewCell.h 3 | // uploadFileDemo 4 | // 5 | // Created by hyjet on 2018/3/5. 6 | // Copyright © 2018年 uploadFileDemo. All rights reserved. 7 | // 8 | 9 | #import 10 | @class CWUploadTask; 11 | 12 | @interface TableViewCell : UITableViewCell 13 | 14 | @property (nonatomic, strong)CWUploadTask *uploadTask; 15 | 16 | + (instancetype)cellWithTableView:(UITableView *)tableView; 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /uploadFileDemo/uploadFileDemo/TableViewCell.m: -------------------------------------------------------------------------------- 1 | // 2 | // TableViewCell.m 3 | // uploadFileDemo 4 | // 5 | // Created by hyjet on 2018/3/5. 6 | // Copyright © 2018年 uploadFileDemo. All rights reserved. 7 | // 8 | 9 | #import "TableViewCell.h" 10 | #import "CWUploadTask.h" 11 | #import "CWFileStreamSeparation.h" 12 | 13 | @interface TableViewCell() 14 | 15 | @property (weak, nonatomic) IBOutlet UIImageView *headImgView; 16 | 17 | @property (weak, nonatomic) IBOutlet UIProgressView *progressView; 18 | 19 | @property (weak, nonatomic) IBOutlet UIButton *startOrStopBtn; 20 | 21 | @property (weak, nonatomic) IBOutlet UILabel *uploadStatusLab; 22 | 23 | @property (weak, nonatomic) IBOutlet UILabel *uploadSizeLab; 24 | 25 | @property (weak, nonatomic) IBOutlet UILabel *rateLab; 26 | 27 | @property (nonatomic, copy) NSString *statusText; 28 | 29 | @end 30 | 31 | @implementation TableViewCell 32 | 33 | static NSString *cellId = @"taskCell"; 34 | 35 | + (instancetype)cellWithTableView:(UITableView *)tableView 36 | { 37 | TableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellId]; 38 | if (cell == nil) { 39 | cell = [[[NSBundle mainBundle] loadNibNamed:NSStringFromClass(self) owner:nil options:nil] lastObject]; 40 | } 41 | [cell registeNotification]; 42 | return cell; 43 | } 44 | 45 | - (void)setUploadTask:(CWUploadTask *)uploadTask 46 | { 47 | _uploadTask = uploadTask; 48 | [self refreshUI:_uploadTask.fileStream]; 49 | } 50 | 51 | #pragma mark - refresh UI 52 | - (void)refreshUI:(CWFileStreamSeparation *)fileStream{ 53 | if (![fileStream.md5String isEqualToString:_uploadTask.ID]) { 54 | return; 55 | } 56 | switch (fileStream.fileStatus) { 57 | case CWUploadStatusUpdownloading: 58 | _statusText = @"上传中..."; 59 | break; 60 | case CWUploadStatusWaiting: 61 | _statusText = @"等待"; 62 | break; 63 | case CWUploadStatusFinished: 64 | _statusText = @"完成"; 65 | break; 66 | case CWUploadStatusFailed: 67 | _statusText = @"失败"; 68 | break; 69 | case CWUploadStatusPaused: 70 | _statusText = @"暂停"; 71 | break; 72 | default: 73 | break; 74 | } 75 | _progressView.progress = fileStream.progressRate; 76 | _uploadSizeLab.text = [NSString stringWithFormat:@"%zd/%zd",fileStream.uploadDateSize,fileStream.fileSize]; 77 | _rateLab.text = [NSString stringWithFormat:@"%.1f%%",fileStream.progressRate*100]; 78 | _uploadStatusLab.text = _statusText; 79 | if (fileStream.fileStatus == CWUploadStatusUpdownloading) { 80 | _startOrStopBtn.selected = YES; 81 | }else{ 82 | _startOrStopBtn.selected = NO; 83 | } 84 | } 85 | 86 | - (void)registeNotification{ 87 | 88 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(taskExeIng:) name:CWUploadTaskExeing object:nil]; 89 | 90 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(taskExeEnd:) name:CWUploadTaskExeEnd object:nil]; 91 | 92 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(taskExeError:) name:CWUploadTaskExeError object:nil]; 93 | 94 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(taskExeSupend:) name:CWUploadTaskExeSuspend object:nil]; 95 | } 96 | 97 | - (void)taskExeIng:(NSNotification *)notification 98 | { 99 | [self refreshUI:notification.userInfo[@"fileStream"]]; 100 | } 101 | 102 | - (void)taskExeSupend:(NSNotification *)notification 103 | { 104 | [self refreshUI:notification.userInfo[@"fileStream"]]; 105 | } 106 | 107 | - (void)taskExeEnd:(NSNotification *)notification 108 | { 109 | CWFileStreamSeparation *fs = notification.userInfo.allValues.firstObject; 110 | [self refreshUI:fs]; 111 | } 112 | 113 | - (void)taskExeError:(NSNotification *)notification 114 | { 115 | CWFileStreamSeparation *fs = notification.userInfo[@"fileStream"]; 116 | NSError *error = (NSError *)notification.userInfo[@"error"]; 117 | NSLog(@"%@,%@",fs,error); 118 | } 119 | 120 | -(void)dealloc 121 | { 122 | [[NSNotificationCenter defaultCenter] removeObserver:self]; 123 | } 124 | 125 | - (void)awakeFromNib { 126 | [super awakeFromNib]; 127 | // Initialization code 128 | } 129 | 130 | - (void)setSelected:(BOOL)selected animated:(BOOL)animated { 131 | [super setSelected:selected animated:animated]; 132 | 133 | // Configure the view for the selected state 134 | } 135 | 136 | @end 137 | -------------------------------------------------------------------------------- /uploadFileDemo/uploadFileDemo/TableViewCell.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 39 | 40 | 41 | 42 | 52 | 62 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | -------------------------------------------------------------------------------- /uploadFileDemo/uploadFileDemo/TableViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // TableViewController.h 3 | // uploadFileDemo 4 | // 5 | // Created by hyjet on 2018/3/5. 6 | // Copyright © 2018年 uploadFileDemo. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface TableViewController : UITableViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /uploadFileDemo/uploadFileDemo/TableViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // TableViewController.m 3 | // uploadFileDemo 4 | // 5 | // Created by hyjet on 2018/3/5. 6 | // Copyright © 2018年 uploadFileDemo. All rights reserved. 7 | // 8 | 9 | #import "TableViewController.h" 10 | #import "TableViewCell.h" 11 | #import "CWFileUploadManager.h" 12 | #import "CWFileStreamSeparation.h" 13 | #import "CWUploadTask.h" 14 | 15 | @interface TableViewController () 16 | 17 | @property (nonatomic, strong)CWFileUploadManager *uploadManager; 18 | 19 | @property (nonatomic, strong)NSMutableArray *taskArr; 20 | 21 | @end 22 | 23 | @implementation TableViewController 24 | 25 | -(NSMutableArray *)taskArr 26 | { 27 | if (!_taskArr) { 28 | _taskArr = [NSMutableArray arrayWithArray:[CWFileUploadManager shardUploadManager].allTasks.allValues]; 29 | } 30 | return _taskArr; 31 | } 32 | 33 | - (CWFileUploadManager *)uploadManager 34 | { 35 | if (!_uploadManager) { 36 | _uploadManager = [CWFileUploadManager shardUploadManager]; 37 | } 38 | return _uploadManager; 39 | } 40 | 41 | - (void)viewDidLoad { 42 | [super viewDidLoad]; 43 | self.tableView.rowHeight = 65.f; 44 | self.title = [NSString stringWithFormat:@"Task Max:%zd",self.uploadManager.uploadMaxNum]; 45 | } 46 | 47 | - (void)didReceiveMemoryWarning { 48 | [super didReceiveMemoryWarning]; 49 | // Dispose of any resources that can be recreated. 50 | } 51 | 52 | - (void)dealloc 53 | { 54 | NSLog(@"TableViewController--dealloc"); 55 | } 56 | 57 | #pragma mark - Table view data source 58 | 59 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { 60 | return 1; 61 | } 62 | 63 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 64 | return self.taskArr.count; 65 | } 66 | 67 | 68 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 69 | TableViewCell *cell = [TableViewCell cellWithTableView:tableView]; 70 | CWUploadTask *task = self.taskArr[indexPath.row]; 71 | cell.uploadTask = task; 72 | return cell; 73 | } 74 | 75 | 76 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 77 | { 78 | CWUploadTask *task = self.taskArr[indexPath.row]; 79 | CWFileStreamSeparation *fs = task.fileStream; 80 | switch (fs.fileStatus) { 81 | case CWUploadStatusWaiting: 82 | NSLog(@"启动上传"); 83 | [task taskResume]; 84 | break; 85 | case CWUploadStatusUpdownloading: 86 | NSLog(@"暂停"); 87 | [task taskCancel]; 88 | break; 89 | case CWUploadStatusFinished: 90 | NSLog(@"上传已经完成"); 91 | break; 92 | case CWUploadStatusFailed: 93 | NSLog(@"启动上传"); 94 | [task taskResume]; 95 | break; 96 | case CWUploadStatusPaused: 97 | NSLog(@"继续上传"); 98 | [task taskResume]; 99 | break; 100 | default: 101 | break; 102 | } 103 | } 104 | 105 | 106 | - (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath { 107 | // Return NO if you do not want the specified item to be editable. 108 | return YES; 109 | } 110 | 111 | -(NSString *)tableView:(UITableView *)tableView titleForDeleteConfirmationButtonForRowAtIndexPath:(NSIndexPath *)indexPath 112 | 113 | { 114 | return @"删除"; 115 | } 116 | 117 | 118 | - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { 119 | if (editingStyle == UITableViewCellEditingStyleDelete) { 120 | // Delete the row from the data source 121 | [self.uploadManager removeUploadTask:self.taskArr[indexPath.row].fileStream]; 122 | [self.taskArr removeObjectAtIndex:indexPath.row]; 123 | [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade]; 124 | } else if (editingStyle == UITableViewCellEditingStyleInsert) { 125 | 126 | } 127 | } 128 | 129 | 130 | /* 131 | #pragma mark - Navigation 132 | 133 | // In a storyboard-based application, you will often want to do a little preparation before navigation 134 | - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { 135 | // Get the new view controller using [segue destinationViewController]. 136 | // Pass the selected object to the new view controller. 137 | } 138 | */ 139 | 140 | 141 | 142 | @end 143 | -------------------------------------------------------------------------------- /uploadFileDemo/uploadFileDemo/Tools/CWFileManager.h: -------------------------------------------------------------------------------- 1 | // 2 | // CWUploadTask.m 3 | // uploadFileDemo 4 | // 5 | // Created by hyjet on 2018/3/9. 6 | // Copyright © 2018年 uploadFileDemo. All rights reserved. 7 | // 8 | #import 9 | 10 | #define uploadPlist @"uploadPlist/upload.plist" 11 | 12 | @interface CWFileManager : NSObject 13 | 14 | #pragma mark - 沙盒目录相关 15 | // 沙盒的主目录路径 16 | + (NSString *)homeDir; 17 | // 沙盒中Documents的目录路径 18 | + (NSString *)documentsDir; 19 | // 沙盒中Library的目录路径 20 | + (NSString *)libraryDir; 21 | // 沙盒中Libarary/Preferences的目录路径 22 | + (NSString *)preferencesDir; 23 | // 沙盒中Library/Caches的目录路径 24 | + (NSString *)cachesDir; 25 | // 沙盒中tmp的目录路径 26 | + (NSString *)tmpDir; 27 | 28 | #pragma mark - 遍历文件夹 29 | /** 30 | 文件遍历 31 | 32 | @param path 目录的绝对路径 33 | @param deep 是否深遍历 (1. 浅遍历:返回当前目录下的所有文件和文件夹; 34 | 2. 深遍历:返回当前目录下及子目录下的所有文件和文件夹) 35 | @return 遍历结果数组 36 | */ 37 | + (NSArray *)listFilesInDirectoryAtPath:(NSString *)path deep:(BOOL)deep; 38 | // 遍历沙盒主目录 39 | + (NSArray *)listFilesInHomeDirectoryByDeep:(BOOL)deep; 40 | // 遍历Documents目录 41 | + (NSArray *)listFilesInDocumentDirectoryByDeep:(BOOL)deep; 42 | // 遍历Library目录 43 | + (NSArray *)listFilesInLibraryDirectoryByDeep:(BOOL)deep; 44 | // 遍历Caches目录 45 | + (NSArray *)listFilesInCachesDirectoryByDeep:(BOOL)deep; 46 | // 遍历tmp目录 47 | + (NSArray *)listFilesInTmpDirectoryByDeep:(BOOL)deep; 48 | //遍历指定文件夹目录 49 | + (NSArray *)listFilesInCoustomDirectoryByDeep:(NSString*)path deepBool:(BOOL)deep; 50 | 51 | #pragma mark - 获取文件属性 52 | // 根据key获取文件某个属性 53 | + (id)attributeOfItemAtPath:(NSString *)path forKey:(NSString *)key; 54 | // 根据key获取文件某个属性(错误信息error) 55 | + (id)attributeOfItemAtPath:(NSString *)path forKey:(NSString *)key error:(NSError **)error; 56 | // 获取文件属性集合 57 | + (NSDictionary *)attributesOfItemAtPath:(NSString *)path; 58 | // 获取文件属性集合(错误信息error) 59 | + (NSDictionary *)attributesOfItemAtPath:(NSString *)path error:(NSError **)error; 60 | 61 | #pragma mark - 创建文件(夹) 62 | // 创建文件夹 63 | + (BOOL)createDirectoryAtPath:(NSString *)path; 64 | // 创建文件夹(错误信息error) 65 | + (BOOL)createDirectoryAtPath:(NSString *)path error:(NSError **)error; 66 | // 创建文件 67 | + (BOOL)createFileAtPath:(NSString *)path; 68 | // 创建文件(错误信息error) 69 | + (BOOL)createFileAtPath:(NSString *)path error:(NSError **)error; 70 | // 创建文件,是否覆盖 71 | + (BOOL)createFileAtPath:(NSString *)path overwrite:(BOOL)overwrite; 72 | // 创建文件,是否覆盖(错误信息error) 73 | + (BOOL)createFileAtPath:(NSString *)path overwrite:(BOOL)overwrite error:(NSError **)error; 74 | // 创建文件,文件内容 75 | + (BOOL)createFileAtPath:(NSString *)path content:(NSObject *)content; 76 | // 创建文件,文件内容(错误信息error) 77 | + (BOOL)createFileAtPath:(NSString *)path content:(NSObject *)content error:(NSError **)error; 78 | // 创建文件,文件内容,是否覆盖 79 | + (BOOL)createFileAtPath:(NSString *)path content:(NSObject *)content overwrite:(BOOL)overwrite; 80 | // 创建文件,文件内容,是否覆盖(错误信息error) 81 | + (BOOL)createFileAtPath:(NSString *)path content:(NSObject *)content overwrite:(BOOL)overwrite error:(NSError **)error; 82 | // 获取创建文件时间 83 | + (NSDate *)creationDateOfItemAtPath:(NSString *)path; 84 | // 获取创建文件时间(错误信息error) 85 | + (NSDate *)creationDateOfItemAtPath:(NSString *)path error:(NSError **)error; 86 | // 获取文件修改时间 87 | + (NSDate *)modificationDateOfItemAtPath:(NSString *)path; 88 | // 获取文件修改时间(错误信息error) 89 | + (NSDate *)modificationDateOfItemAtPath:(NSString *)path error:(NSError **)error; 90 | 91 | #pragma mark - 删除文件(夹) 92 | // 删除文件 93 | + (BOOL)removeItemAtPath:(NSString *)path; 94 | // 删除文件(错误信息error) 95 | + (BOOL)removeItemAtPath:(NSString *)path error:(NSError **)error; 96 | // 清空Caches文件夹 97 | + (BOOL)clearCachesDirectory; 98 | // 清空tmp文件夹 99 | + (BOOL)clearTmpDirectory; 100 | 101 | #pragma mark - 复制文件(夹) 102 | // 复制文件 103 | + (BOOL)copyItemAtPath:(NSString *)path toPath:(NSString *)toPath; 104 | // 复制文件(错误信息error) 105 | + (BOOL)copyItemAtPath:(NSString *)path toPath:(NSString *)toPath error:(NSError **)error; 106 | // 复制文件,是否覆盖 107 | + (BOOL)copyItemAtPath:(NSString *)path toPath:(NSString *)toPath overwrite:(BOOL)overwrite; 108 | // 复制文件,是否覆盖(错误信息error) 109 | + (BOOL)copyItemAtPath:(NSString *)path toPath:(NSString *)toPath overwrite:(BOOL)overwrite error:(NSError **)error; 110 | 111 | #pragma mark - 移动文件(夹) 112 | // 移动文件 113 | + (BOOL)moveItemAtPath:(NSString *)path toPath:(NSString *)toPath; 114 | // 移动文件(错误信息error) 115 | + (BOOL)moveItemAtPath:(NSString *)path toPath:(NSString *)toPath error:(NSError **)error; 116 | // 移动文件,是否覆盖 117 | + (BOOL)moveItemAtPath:(NSString *)path toPath:(NSString *)toPath overwrite:(BOOL)overwrite; 118 | // 移动文件,是否覆盖(错误信息error) 119 | + (BOOL)moveItemAtPath:(NSString *)path toPath:(NSString *)toPath overwrite:(BOOL)overwrite error:(NSError **)error; 120 | 121 | #pragma mark - 根据URL获取文件名 122 | // 根据文件路径获取文件名称,是否需要后缀 123 | + (NSString *)fileNameAtPath:(NSString *)path suffix:(BOOL)suffix; 124 | // 获取文件所在的文件夹路径 125 | + (NSString *)directoryAtPath:(NSString *)path; 126 | // 根据文件路径获取文件扩展类型 127 | + (NSString *)suffixAtPath:(NSString *)path; 128 | 129 | #pragma mark - 判断文件(夹)是否存在 130 | // 判断文件路径是否存在 131 | + (BOOL)isExistsAtPath:(NSString *)path; 132 | // 判断路径是否为空(判空条件是文件大小为0,或者是文件夹下没有子文件) 133 | + (BOOL)isEmptyItemAtPath:(NSString *)path; 134 | // 判断路径是否为空(错误信息error) 135 | + (BOOL)isEmptyItemAtPath:(NSString *)path error:(NSError **)error; 136 | // 判断目录是否是文件夹 137 | + (BOOL)isDirectoryAtPath:(NSString *)path; 138 | // 判断目录是否是文件夹(错误信息error) 139 | + (BOOL)isDirectoryAtPath:(NSString *)path error:(NSError **)error; 140 | // 判断目录是否是文件 141 | + (BOOL)isFileAtPath:(NSString *)path; 142 | // 判断目录是否是文件(错误信息error) 143 | + (BOOL)isFileAtPath:(NSString *)path error:(NSError **)error; 144 | // 判断目录是否可以执行 145 | + (BOOL)isExecutableItemAtPath:(NSString *)path; 146 | // 判断目录是否可读 147 | + (BOOL)isReadableItemAtPath:(NSString *)path; 148 | // 判断目录是否可写 149 | + (BOOL)isWritableItemAtPath:(NSString *)path; 150 | 151 | #pragma mark - 获取文件(夹)大小 152 | // 获取目录大小 153 | + (NSNumber *)sizeOfItemAtPath:(NSString *)path; 154 | // 获取目录大小(错误信息error) 155 | + (NSNumber *)sizeOfItemAtPath:(NSString *)path error:(NSError **)error; 156 | // 获取文件大小 157 | + (NSNumber *)sizeOfFileAtPath:(NSString *)path; 158 | // 获取文件大小(错误信息error) 159 | + (NSNumber *)sizeOfFileAtPath:(NSString *)path error:(NSError **)error; 160 | // 获取文件夹大小 161 | + (NSNumber *)sizeOfDirectoryAtPath:(NSString *)path; 162 | // 获取文件夹大小(错误信息error) 163 | + (NSNumber *)sizeOfDirectoryAtPath:(NSString *)path error:(NSError **)error; 164 | 165 | // 获取目录大小,返回格式化后的数值 166 | + (NSString *)sizeFormattedOfItemAtPath:(NSString *)path; 167 | // 获取目录大小,返回格式化后的数值(错误信息error) 168 | + (NSString *)sizeFormattedOfItemAtPath:(NSString *)path error:(NSError **)error; 169 | // 获取文件大小,返回格式化后的数值 170 | + (NSString *)sizeFormattedOfFileAtPath:(NSString *)path; 171 | // 获取文件大小,返回格式化后的数值(错误信息error) 172 | + (NSString *)sizeFormattedOfFileAtPath:(NSString *)path error:(NSError **)error; 173 | // 获取文件夹大小,返回格式化后的数值 174 | + (NSString *)sizeFormattedOfDirectoryAtPath:(NSString *)path; 175 | // 获取文件夹大小,返回格式化后的数值(错误信息error) 176 | + (NSString *)sizeFormattedOfDirectoryAtPath:(NSString *)path error:(NSError **)error; 177 | 178 | #pragma mark - 写入文件内容 179 | // 写入文件内容 180 | + (BOOL)writeFileAtPath:(NSString *)path content:(NSObject *)content; 181 | // 写入文件内容(错误信息error) 182 | + (BOOL)writeFileAtPath:(NSString *)path content:(NSObject *)content error:(NSError **)error; 183 | 184 | @end 185 | -------------------------------------------------------------------------------- /uploadFileDemo/uploadFileDemo/Tools/CWFileManager.m: -------------------------------------------------------------------------------- 1 | // 2 | // CWUploadTask.m 3 | // uploadFileDemo 4 | // 5 | // Created by hyjet on 2018/3/9. 6 | // Copyright © 2018年 uploadFileDemo. All rights reserved. 7 | 8 | #import "CWFileManager.h" 9 | 10 | @interface CWFileManager () 11 | 12 | @property (strong, nonatomic) NSFileManager *manager; 13 | 14 | @end 15 | 16 | 17 | @implementation CWFileManager 18 | 19 | #pragma mark - 沙盒目录相关 20 | + (NSString *)homeDir { 21 | return NSHomeDirectory(); 22 | } 23 | 24 | + (NSString *)documentsDir { 25 | return [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject]; 26 | } 27 | 28 | + (NSString *)libraryDir { 29 | return [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) lastObject];; 30 | } 31 | 32 | + (NSString *)preferencesDir { 33 | NSString *libraryDir = [self libraryDir]; 34 | return [libraryDir stringByAppendingPathComponent:@"Preferences"]; 35 | } 36 | 37 | + (NSString *)cachesDir { 38 | return [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) firstObject]; 39 | } 40 | 41 | + (NSString *)tmpDir { 42 | return NSTemporaryDirectory(); 43 | } 44 | #pragma mark - 遍历文件夹 45 | + (NSArray *)listFilesInDirectoryAtPath:(NSString *)path deep:(BOOL)deep { 46 | NSArray *listArr; 47 | NSError *error; 48 | NSFileManager *manager = [NSFileManager defaultManager]; 49 | if (deep) { 50 | // 深遍历 51 | NSArray *deepArr = [manager subpathsOfDirectoryAtPath:path error:&error]; 52 | if (!error) { 53 | listArr = deepArr; 54 | }else { 55 | listArr = nil; 56 | } 57 | }else { 58 | // 浅遍历 59 | NSArray *shallowArr = [manager contentsOfDirectoryAtPath:path error:&error]; 60 | if (!error) { 61 | listArr = shallowArr; 62 | }else { 63 | listArr = nil; 64 | } 65 | } 66 | return listArr; 67 | } 68 | 69 | + (NSArray *)listFilesInHomeDirectoryByDeep:(BOOL)deep { 70 | return [self listFilesInDirectoryAtPath:[self homeDir] deep:deep]; 71 | } 72 | 73 | + (NSArray *)listFilesInLibraryDirectoryByDeep:(BOOL)deep { 74 | return [self listFilesInDirectoryAtPath:[self libraryDir] deep:deep]; 75 | } 76 | 77 | + (NSArray *)listFilesInDocumentDirectoryByDeep:(BOOL)deep { 78 | return [self listFilesInDirectoryAtPath:[self documentsDir] deep:deep]; 79 | } 80 | 81 | + (NSArray *)listFilesInTmpDirectoryByDeep:(BOOL)deep { 82 | return [self listFilesInDirectoryAtPath:[self tmpDir] deep:deep]; 83 | } 84 | 85 | + (NSArray *)listFilesInCachesDirectoryByDeep:(BOOL)deep { 86 | return [self listFilesInDirectoryAtPath:[self cachesDir] deep:deep]; 87 | } 88 | 89 | + (NSArray *)listFilesInCoustomDirectoryByDeep:(NSString*)path deepBool:(BOOL)deep{ 90 | if (![CWFileManager isExistsAtPath:path]) { 91 | return @[]; 92 | } 93 | return [self listFilesInDirectoryAtPath:path deep:deep]; 94 | } 95 | 96 | #pragma mark - 获取文件属性 97 | + (id)attributeOfItemAtPath:(NSString *)path forKey:(NSString *)key { 98 | return [[self attributesOfItemAtPath:path] objectForKey:key]; 99 | } 100 | 101 | + (id)attributeOfItemAtPath:(NSString *)path forKey:(NSString *)key error:(NSError *__autoreleasing *)error { 102 | return [[self attributesOfItemAtPath:path error:error] objectForKey:key]; 103 | } 104 | 105 | + (NSDictionary *)attributesOfItemAtPath:(NSString *)path { 106 | return [self attributesOfItemAtPath:path error:nil]; 107 | } 108 | 109 | + (NSDictionary *)attributesOfItemAtPath:(NSString *)path error:(NSError *__autoreleasing *)error { 110 | return [[NSFileManager defaultManager] attributesOfItemAtPath:path error:error]; 111 | } 112 | 113 | #pragma mark - 创建文件(夹) 114 | + (BOOL)createDirectoryAtPath:(NSString *)path { 115 | return [self createDirectoryAtPath:path error:nil]; 116 | } 117 | 118 | + (BOOL)createDirectoryAtPath:(NSString *)path error:(NSError *__autoreleasing *)error { 119 | NSFileManager *manager = [NSFileManager defaultManager]; 120 | BOOL isSuccess = [manager createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:error]; 121 | return isSuccess; 122 | } 123 | 124 | + (BOOL)createFileAtPath:(NSString *)path { 125 | return [self createFileAtPath:path content:nil overwrite:YES error:nil]; 126 | } 127 | 128 | + (BOOL)createFileAtPath:(NSString *)path error:(NSError *__autoreleasing *)error { 129 | return [self createFileAtPath:path content:nil overwrite:YES error:error]; 130 | } 131 | 132 | + (BOOL)createFileAtPath:(NSString *)path overwrite:(BOOL)overwrite { 133 | return [self createFileAtPath:path content:nil overwrite:overwrite error:nil]; 134 | } 135 | 136 | + (BOOL)createFileAtPath:(NSString *)path overwrite:(BOOL)overwrite error:(NSError *__autoreleasing *)error { 137 | return [self createFileAtPath:path content:nil overwrite:overwrite error:error]; 138 | } 139 | 140 | + (BOOL)createFileAtPath:(NSString *)path content:(NSObject *)content { 141 | return [self createFileAtPath:path content:content overwrite:YES error:nil]; 142 | } 143 | 144 | + (BOOL)createFileAtPath:(NSString *)path content:(NSObject *)content error:(NSError *__autoreleasing *)error { 145 | return [self createFileAtPath:path content:content overwrite:YES error:error]; 146 | } 147 | 148 | + (BOOL)createFileAtPath:(NSString *)path content:(NSObject *)content overwrite:(BOOL)overwrite { 149 | return [self createFileAtPath:path content:content overwrite:overwrite error:nil]; 150 | } 151 | 152 | + (BOOL)createFileAtPath:(NSString *)path content:(NSObject *)content overwrite:(BOOL)overwrite error:(NSError *__autoreleasing *)error { 153 | // 如果文件夹路径不存在,那么先创建文件夹 154 | NSString *directoryPath = [self directoryAtPath:path]; 155 | if (![self isExistsAtPath:directoryPath]) { 156 | // 创建文件夹 157 | if (![self createDirectoryAtPath:directoryPath error:error]) { 158 | return NO; 159 | } 160 | } 161 | // 如果文件存在,并不想覆盖,那么直接返回YES。 162 | if (!overwrite) { 163 | if ([self isExistsAtPath:path]) { 164 | return YES; 165 | } 166 | } 167 | // 创建文件 168 | BOOL isSuccess = [[NSFileManager defaultManager] createFileAtPath:path contents:nil attributes:nil]; 169 | if (content) { 170 | [self writeFileAtPath:path content:content error:error]; 171 | } 172 | return isSuccess; 173 | } 174 | 175 | + (NSDate *)creationDateOfItemAtPath:(NSString *)path { 176 | return [self creationDateOfItemAtPath:path error:nil]; 177 | } 178 | 179 | + (NSDate *)creationDateOfItemAtPath:(NSString *)path error:(NSError *__autoreleasing *)error { 180 | return (NSDate *)[self attributeOfItemAtPath:path forKey:NSFileCreationDate error:error]; 181 | } 182 | 183 | + (NSDate *)modificationDateOfItemAtPath:(NSString *)path { 184 | return [self modificationDateOfItemAtPath:path error:nil]; 185 | } 186 | 187 | + (NSDate *)modificationDateOfItemAtPath:(NSString *)path error:(NSError *__autoreleasing *)error { 188 | return (NSDate *)[self attributeOfItemAtPath:path forKey:NSFileModificationDate error:error]; 189 | } 190 | 191 | #pragma mark - 删除文件(夹) 192 | + (BOOL)removeItemAtPath:(NSString *)path { 193 | return [self removeItemAtPath:path error:nil]; 194 | } 195 | 196 | + (BOOL)removeItemAtPath:(NSString *)path error:(NSError *__autoreleasing *)error { 197 | return [[NSFileManager defaultManager] removeItemAtPath:path error:error]; 198 | } 199 | 200 | + (BOOL)clearCachesDirectory { 201 | NSArray *subFiles = [self listFilesInCachesDirectoryByDeep:NO]; 202 | BOOL isSuccess = YES; 203 | 204 | for (NSString *file in subFiles) { 205 | NSString *absolutePath = [[self cachesDir] stringByAppendingPathComponent:file]; 206 | isSuccess &= [self removeItemAtPath:absolutePath]; 207 | } 208 | return isSuccess; 209 | } 210 | 211 | + (BOOL)clearTmpDirectory { 212 | NSArray *subFiles = [self listFilesInTmpDirectoryByDeep:NO]; 213 | BOOL isSuccess = YES; 214 | 215 | for (NSString *file in subFiles) { 216 | NSString *absolutePath = [[self tmpDir] stringByAppendingPathComponent:file]; 217 | isSuccess &= [self removeItemAtPath:absolutePath]; 218 | } 219 | return isSuccess; 220 | } 221 | 222 | #pragma mark - 复制文件(夹) 223 | + (BOOL)copyItemAtPath:(NSString *)path toPath:(NSString *)toPath { 224 | return [self copyItemAtPath:path toPath:toPath overwrite:NO error:nil]; 225 | } 226 | 227 | + (BOOL)copyItemAtPath:(NSString *)path toPath:(NSString *)toPath error:(NSError *__autoreleasing *)error { 228 | return [self copyItemAtPath:path toPath:toPath overwrite:NO error:error]; 229 | } 230 | 231 | + (BOOL)copyItemAtPath:(NSString *)path toPath:(NSString *)toPath overwrite:(BOOL)overwrite { 232 | return [self copyItemAtPath:path toPath:toPath overwrite:overwrite error:nil]; 233 | } 234 | 235 | + (BOOL)copyItemAtPath:(NSString *)path toPath:(NSString *)toPath overwrite:(BOOL)overwrite error:(NSError *__autoreleasing *)error { 236 | // 先要保证源文件路径存在,不然抛出异常 237 | if (![self isExistsAtPath:path]) { 238 | [NSException raise:@"非法的源文件路径" format:@"源文件路径%@不存在,请检查源文件路径", path]; 239 | return NO; 240 | } 241 | NSString *toDirPath = [self directoryAtPath:toPath]; 242 | if (![self isExistsAtPath:toDirPath]) { 243 | // 创建复制路径 244 | if (![self createDirectoryAtPath:toDirPath error:error]) { 245 | return NO; 246 | } 247 | } 248 | // 如果覆盖,那么先删掉原文件 249 | if (overwrite) { 250 | if ([self isExistsAtPath:toPath]) { 251 | [self removeItemAtPath:toPath error:error]; 252 | } 253 | } 254 | // 复制文件 255 | BOOL isSuccess = [[NSFileManager defaultManager] copyItemAtPath:path toPath:toPath error:error]; 256 | 257 | return isSuccess; 258 | } 259 | 260 | #pragma mark - 移动文件(夹) 261 | + (BOOL)moveItemAtPath:(NSString *)path toPath:(NSString *)toPath { 262 | return [self moveItemAtPath:path toPath:toPath overwrite:NO error:nil]; 263 | } 264 | 265 | + (BOOL)moveItemAtPath:(NSString *)path toPath:(NSString *)toPath error:(NSError *__autoreleasing *)error { 266 | return [self moveItemAtPath:path toPath:toPath overwrite:NO error:error]; 267 | } 268 | 269 | + (BOOL)moveItemAtPath:(NSString *)path toPath:(NSString *)toPath overwrite:(BOOL)overwrite { 270 | return [self moveItemAtPath:path toPath:toPath overwrite:overwrite error:nil]; 271 | } 272 | 273 | + (BOOL)moveItemAtPath:(NSString *)path toPath:(NSString *)toPath overwrite:(BOOL)overwrite error:(NSError *__autoreleasing *)error { 274 | // 先要保证源文件路径存在,不然抛出异常 275 | if (![self isExistsAtPath:path]) { 276 | [NSException raise:@"非法的源文件路径" format:@"源文件路径%@不存在,请检查源文件路径", path]; 277 | return NO; 278 | } 279 | NSString *toDirPath = [self directoryAtPath:toPath]; 280 | if (![self isExistsAtPath:toDirPath]) { 281 | // 创建移动路径 282 | if (![self createDirectoryAtPath:toDirPath error:error]) { 283 | return NO; 284 | } 285 | } 286 | // 如果覆盖,那么先删掉原文件 287 | if ([self isExistsAtPath:toPath]) { 288 | if (overwrite) { 289 | [self removeItemAtPath:toPath error:error]; 290 | }else { 291 | [self removeItemAtPath:path error:error]; 292 | return YES; 293 | } 294 | } 295 | 296 | // 移动文件 297 | BOOL isSuccess = [[NSFileManager defaultManager] moveItemAtPath:path toPath:toPath error:error]; 298 | 299 | return isSuccess; 300 | } 301 | 302 | #pragma mark - 根据URL获取文件名 303 | + (NSString *)fileNameAtPath:(NSString *)path suffix:(BOOL)suffix { 304 | NSString *fileName = [path lastPathComponent]; 305 | if (!suffix) { 306 | fileName = [fileName stringByDeletingPathExtension]; 307 | } 308 | return fileName; 309 | } 310 | 311 | + (NSString *)directoryAtPath:(NSString *)path { 312 | return [path stringByDeletingLastPathComponent]; 313 | } 314 | 315 | + (NSString *)suffixAtPath:(NSString *)path { 316 | return [path pathExtension]; 317 | } 318 | 319 | #pragma mark - 判断文件(夹)是否存在 320 | + (BOOL)isExistsAtPath:(NSString *)path { 321 | return [[NSFileManager defaultManager] fileExistsAtPath:path]; 322 | } 323 | 324 | + (BOOL)isEmptyItemAtPath:(NSString *)path { 325 | return [self isEmptyItemAtPath:path error:nil]; 326 | } 327 | 328 | + (BOOL)isEmptyItemAtPath:(NSString *)path error:(NSError *__autoreleasing *)error { 329 | return ([self isFileAtPath:path error:error] && 330 | [[self sizeOfItemAtPath:path error:error] intValue] == 0) || 331 | ([self isDirectoryAtPath:path error:error] && 332 | [[self listFilesInDirectoryAtPath:path deep:NO] count] == 0); 333 | } 334 | 335 | + (BOOL)isDirectoryAtPath:(NSString *)path { 336 | return [self isDirectoryAtPath:path error:nil]; 337 | } 338 | 339 | + (BOOL)isDirectoryAtPath:(NSString *)path error:(NSError *__autoreleasing *)error { 340 | return ([self attributeOfItemAtPath:path forKey:NSFileType error:error] == NSFileTypeDirectory); 341 | } 342 | 343 | + (BOOL)isFileAtPath:(NSString *)path { 344 | return [self isFileAtPath:path error:nil]; 345 | } 346 | 347 | + (BOOL)isFileAtPath:(NSString *)path error:(NSError *__autoreleasing *)error { 348 | return ([self attributeOfItemAtPath:path forKey:NSFileType error:error] == NSFileTypeRegular); 349 | } 350 | 351 | + (BOOL)isExecutableItemAtPath:(NSString *)path { 352 | return [[NSFileManager defaultManager] isExecutableFileAtPath:path]; 353 | } 354 | 355 | + (BOOL)isReadableItemAtPath:(NSString *)path { 356 | return [[NSFileManager defaultManager] isReadableFileAtPath:path]; 357 | } 358 | + (BOOL)isWritableItemAtPath:(NSString *)path { 359 | return [[NSFileManager defaultManager] isWritableFileAtPath:path]; 360 | } 361 | 362 | #pragma mark - 获取文件(夹)大小 363 | + (NSNumber *)sizeOfItemAtPath:(NSString *)path { 364 | return [self sizeOfItemAtPath:path error:nil]; 365 | } 366 | 367 | + (NSNumber *)sizeOfItemAtPath:(NSString *)path error:(NSError *__autoreleasing *)error { 368 | return (NSNumber *)[self attributeOfItemAtPath:path forKey:NSFileSize error:error]; 369 | } 370 | 371 | + (NSNumber *)sizeOfFileAtPath:(NSString *)path { 372 | return [self sizeOfFileAtPath:path error:nil]; 373 | } 374 | 375 | + (NSNumber *)sizeOfFileAtPath:(NSString *)path error:(NSError *__autoreleasing *)error { 376 | if ([self isFileAtPath:path error:error]) { 377 | return [self sizeOfItemAtPath:path error:error]; 378 | } 379 | return nil; 380 | } 381 | 382 | + (NSNumber *)sizeOfDirectoryAtPath:(NSString *)path { 383 | return [self sizeOfDirectoryAtPath:path error:nil]; 384 | } 385 | 386 | + (NSNumber *)sizeOfDirectoryAtPath:(NSString *)path error:(NSError *__autoreleasing *)error { 387 | if ([self isDirectoryAtPath:path error:error]) { 388 | NSArray *subPaths = [self listFilesInDirectoryAtPath:path deep:YES]; 389 | NSEnumerator *contentsEnumurator = [subPaths objectEnumerator]; 390 | 391 | NSString *file; 392 | unsigned long long int folderSize = 0; 393 | 394 | while (file = [contentsEnumurator nextObject]) { 395 | NSDictionary *fileAttributes = [[NSFileManager defaultManager] attributesOfItemAtPath:[path stringByAppendingPathComponent:file] error:nil]; 396 | folderSize += [[fileAttributes objectForKey:NSFileSize] intValue]; 397 | } 398 | return [NSNumber numberWithUnsignedLongLong:folderSize]; 399 | } 400 | return nil; 401 | } 402 | 403 | + (NSString *)sizeFormattedOfItemAtPath:(NSString *)path { 404 | return [self sizeFormattedOfItemAtPath:path error:nil]; 405 | } 406 | 407 | + (NSString *)sizeFormattedOfItemAtPath:(NSString *)path error:(NSError *__autoreleasing *)error { 408 | NSNumber *size = [self sizeOfItemAtPath:path error:error]; 409 | if (size) { 410 | return [self sizeFormatted:size]; 411 | } 412 | return nil; 413 | } 414 | 415 | + (NSString *)sizeFormattedOfFileAtPath:(NSString *)path { 416 | return [self sizeFormattedOfFileAtPath:path error:nil]; 417 | } 418 | 419 | + (NSString *)sizeFormattedOfFileAtPath:(NSString *)path error:(NSError *__autoreleasing *)error { 420 | NSNumber *size = [self sizeOfFileAtPath:path error:error]; 421 | if (size) { 422 | return [self sizeFormatted:size]; 423 | } 424 | return nil; 425 | } 426 | 427 | + (NSString *)sizeFormattedOfDirectoryAtPath:(NSString *)path { 428 | return [self sizeFormattedOfDirectoryAtPath:path error:nil]; 429 | } 430 | 431 | + (NSString *)sizeFormattedOfDirectoryAtPath:(NSString *)path error:(NSError *__autoreleasing *)error { 432 | NSNumber *size = [self sizeOfDirectoryAtPath:path error:error]; 433 | if (size) { 434 | return [self sizeFormatted:size]; 435 | } 436 | return nil; 437 | } 438 | 439 | #pragma mark - 写入文件内容 440 | + (BOOL)writeFileAtPath:(NSString *)path content:(NSObject *)content { 441 | return [self writeFileAtPath:path content:content error:nil]; 442 | } 443 | 444 | + (BOOL)writeFileAtPath:(NSString *)path content:(NSObject *)content error:(NSError *__autoreleasing *)error { 445 | if (!content) { 446 | [NSException raise:@"非法的文件内容" format:@"文件内容不能为nil"]; 447 | return NO; 448 | } 449 | if ([self isExistsAtPath:path]) { 450 | if ([content isKindOfClass:[NSMutableArray class]]) { 451 | [(NSMutableArray *)content writeToFile:path atomically:YES]; 452 | }else if ([content isKindOfClass:[NSArray class]]) { 453 | [(NSArray *)content writeToFile:path atomically:YES]; 454 | }else if ([content isKindOfClass:[NSMutableData class]]) { 455 | [(NSMutableData *)content writeToFile:path atomically:YES]; 456 | }else if ([content isKindOfClass:[NSData class]]) { 457 | [(NSData *)content writeToFile:path atomically:YES]; 458 | }else if ([content isKindOfClass:[NSMutableDictionary class]]) { 459 | [(NSMutableDictionary *)content writeToFile:path atomically:YES]; 460 | }else if ([content isKindOfClass:[NSDictionary class]]) { 461 | [(NSDictionary *)content writeToFile:path atomically:YES]; 462 | }else if ([content isKindOfClass:[NSJSONSerialization class]]) { 463 | [(NSDictionary *)content writeToFile:path atomically:YES]; 464 | }else if ([content isKindOfClass:[NSMutableString class]]) { 465 | [[((NSString *)content) dataUsingEncoding:NSUTF8StringEncoding] writeToFile:path atomically:YES]; 466 | }else if ([content isKindOfClass:[NSString class]]) { 467 | [[((NSString *)content) dataUsingEncoding:NSUTF8StringEncoding] writeToFile:path atomically:YES]; 468 | }else if ([content isKindOfClass:[UIImage class]]) { 469 | [UIImagePNGRepresentation((UIImage *)content) writeToFile:path atomically:YES]; 470 | }else if ([content conformsToProtocol:@protocol(NSCoding)]) { 471 | [NSKeyedArchiver archiveRootObject:content toFile:path]; 472 | }else { 473 | [NSException raise:@"非法的文件内容" format:@"文件类型%@异常,无法被处理。", NSStringFromClass([content class])]; 474 | 475 | return NO; 476 | } 477 | }else { 478 | return NO; 479 | } 480 | return YES; 481 | } 482 | 483 | #pragma mark - private methods 484 | + (BOOL)isNotError:(NSError **)error { 485 | return ((error == nil) || ((*error) == nil)); 486 | } 487 | 488 | +(NSString *)sizeFormatted:(NSNumber *)size { 489 | return [NSByteCountFormatter stringFromByteCount:[size unsignedLongLongValue] countStyle:NSByteCountFormatterCountStyleFile]; 490 | } 491 | 492 | @end 493 | -------------------------------------------------------------------------------- /uploadFileDemo/uploadFileDemo/Tools/PrefixHeader.pch: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // PrefixHeader.pch 4 | // uploadFileDemo 5 | // 6 | // Created by hyjet on 2018/3/5. 7 | // Copyright © 2018年 uploadFileDemo. All rights reserved. 8 | // 9 | 10 | #ifndef PrefixHeader_pch 11 | #define PrefixHeader_pch 12 | 13 | #define screenSize [UIScreen mainScreen].bounds.size 14 | #define screenWidth [UIScreen mainScreen].bounds.size.width 15 | #define screenHeight [UIScreen mainScreen].bounds.size.height 16 | 17 | 18 | #define BASE_URL @"" 19 | #define TAPI @"" 20 | #define DAPI @"" 21 | #define PAPI @"" 22 | 23 | #define CURRENT_API PAPI 24 | 25 | #endif /* PrefixHeader_pch */ 26 | -------------------------------------------------------------------------------- /uploadFileDemo/uploadFileDemo/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // uploadFileDemo 4 | // 5 | // Created by hyjet on 2018/3/5. 6 | // Copyright © 2018年 uploadFileDemo. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ViewController : UIViewController 12 | 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /uploadFileDemo/uploadFileDemo/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // uploadFileDemo 4 | // 5 | // Created by hyjet on 2018/3/5. 6 | // Copyright © 2018年 uploadFileDemo. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | #import "CWFileManager.h" 11 | #import "CWFileStreamSeparation.h" 12 | #import "CWFileUploadManager.h" 13 | #import "CWUploadTask.h" 14 | 15 | @interface ViewController () 16 | 17 | @property (weak, nonatomic) IBOutlet UILabel *videoPathLab; 18 | 19 | 20 | @end 21 | 22 | @implementation ViewController 23 | 24 | - (void)viewDidLoad { 25 | [super viewDidLoad]; 26 | NSLog(@"uploadWaitTasks:%@",[CWFileUploadManager shardUploadManager].uploadWaitTasks); 27 | NSLog(@"uploadEndTasks:%@",[CWFileUploadManager shardUploadManager].uploadEndTasks); 28 | NSLog(@"uploadingTasks:%@",[CWFileUploadManager shardUploadManager].uploadingTasks); 29 | } 30 | 31 | - (IBAction)selectVideo:(UIButton *)sender { 32 | NSLog(@"从相册选择"); 33 | UIImagePickerController *picker=[[UIImagePickerController alloc] init]; 34 | 35 | picker.delegate=self; 36 | picker.allowsEditing=NO; 37 | picker.videoMaximumDuration = 1.0;//视频最长长度 38 | picker.videoQuality = UIImagePickerControllerQualityTypeMedium;//视频质量 39 | 40 | //媒体类型:@"public.movie" 为视频 @"public.image" 为图片 41 | //这里只选择展示视频 42 | picker.mediaTypes = [NSArray arrayWithObjects:@"public.movie", nil]; 43 | 44 | picker.sourceType= UIImagePickerControllerSourceTypeSavedPhotosAlbum; 45 | 46 | [self presentViewController:picker animated:YES completion:^{ 47 | 48 | }]; 49 | 50 | } 51 | 52 | - (IBAction)startExeUpload:(UIButton *)sender { 53 | CWUploadTask *task = [[CWFileUploadManager shardUploadManager] createUploadTask:self.videoPathLab.text]; 54 | [task taskResume]; 55 | } 56 | 57 | - (NSMutableURLRequest *)setUpRequest{ 58 | NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"%@/upload/file",CURRENT_API]]; 59 | NSMutableURLRequest* request=[NSMutableURLRequest requestWithURL:url]; 60 | request.HTTPMethod=@"POST"; 61 | [request setValue:[NSString stringWithFormat:@"multipart/form-data; boundary=%@",@"1a2b3c"] forHTTPHeaderField:@"Content-Type"]; 62 | [request setValue:@"v1" forHTTPHeaderField:@"api_version"]; 63 | return request; 64 | } 65 | 66 | #pragma mark UIImagePickerControllerDelegate 67 | - (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info{ 68 | 69 | NSString *mediaType=[info objectForKey:UIImagePickerControllerMediaType]; 70 | 71 | if ([mediaType isEqualToString:@"public.movie"]){ 72 | //如果是视频 73 | NSURL *url = info[UIImagePickerControllerMediaURL];//获得视频的URL 74 | //保存至沙盒路径 75 | NSString *fileFolder = [[CWFileManager cachesDir] stringByAppendingString:@"/video"]; 76 | if (![CWFileManager isExistsAtPath:fileFolder]) { 77 | [CWFileManager createDirectoryAtPath:fileFolder]; 78 | } 79 | NSString *originalPath = [url.absoluteString stringByReplacingOccurrencesOfString:@"file://" withString:@""]; 80 | NSString *videoName = [NSString stringWithFormat:@"%@.mp4", [CWFileStreamSeparation fileKeyMD5WithPath:originalPath]]; 81 | NSString *sandboxPath = [fileFolder stringByAppendingPathComponent:videoName]; 82 | [CWFileManager moveItemAtPath:originalPath toPath:sandboxPath overwrite:YES error:nil]; 83 | NSLog(@"url %@",url); 84 | self.videoPathLab.text = sandboxPath; 85 | } 86 | 87 | [self dismissViewControllerAnimated:YES completion:nil]; 88 | } 89 | 90 | @end 91 | -------------------------------------------------------------------------------- /uploadFileDemo/uploadFileDemo/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // uploadFileDemo 4 | // 5 | // Created by hyjet on 2018/3/5. 6 | // Copyright © 2018年 uploadFileDemo. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /uploadFileDemo/uploadFileDemoTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /uploadFileDemo/uploadFileDemoTests/uploadFileDemoTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // uploadFileDemoTests.m 3 | // uploadFileDemoTests 4 | // 5 | // Created by hyjet on 2018/3/5. 6 | // Copyright © 2018年 uploadFileDemo. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface uploadFileDemoTests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation uploadFileDemoTests 16 | 17 | - (void)setUp { 18 | [super setUp]; 19 | // Put setup code here. This method is called before the invocation of each test method in the class. 20 | } 21 | 22 | - (void)tearDown { 23 | // Put teardown code here. This method is called after the invocation of each test method in the class. 24 | [super tearDown]; 25 | } 26 | 27 | - (void)testExample { 28 | // This is an example of a functional test case. 29 | // Use XCTAssert and related functions to verify your tests produce the correct results. 30 | } 31 | 32 | - (void)testPerformanceExample { 33 | // This is an example of a performance test case. 34 | [self measureBlock:^{ 35 | // Put the code you want to measure the time of here. 36 | }]; 37 | } 38 | 39 | @end 40 | -------------------------------------------------------------------------------- /uploadFileDemo/uploadFileDemoUITests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /uploadFileDemo/uploadFileDemoUITests/uploadFileDemoUITests.m: -------------------------------------------------------------------------------- 1 | // 2 | // uploadFileDemoUITests.m 3 | // uploadFileDemoUITests 4 | // 5 | // Created by hyjet on 2018/3/5. 6 | // Copyright © 2018年 uploadFileDemo. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface uploadFileDemoUITests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation uploadFileDemoUITests 16 | 17 | - (void)setUp { 18 | [super setUp]; 19 | 20 | // Put setup code here. This method is called before the invocation of each test method in the class. 21 | 22 | // In UI tests it is usually best to stop immediately when a failure occurs. 23 | self.continueAfterFailure = NO; 24 | // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method. 25 | [[[XCUIApplication alloc] init] launch]; 26 | 27 | // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this. 28 | } 29 | 30 | - (void)tearDown { 31 | // Put teardown code here. This method is called after the invocation of each test method in the class. 32 | [super tearDown]; 33 | } 34 | 35 | - (void)testExample { 36 | // Use recording to get started writing UI tests. 37 | // Use XCTAssert and related functions to verify your tests produce the correct results. 38 | } 39 | 40 | @end 41 | --------------------------------------------------------------------------------