在日常開發(fā)中,我們都在用http(s) 來進(jìn)行網(wǎng)絡(luò)傳輸?shù)牟ǘ恚蟼飨螺d等任務(wù)的晨逝,前段時間聽說要用ftp來上傳資源,當(dāng)時還是一臉懵逼的懦铺。后來東拼西湊的算是勉強(qiáng)搞定了捉貌。
在iOS端的ftp上傳使用的是CFNetWork框架,它處于核心服務(wù)框架中,提供了一個抽象化的網(wǎng)絡(luò)協(xié)議庫冬念。使用CFNetWork框架中的CFFTPStream類提供的API能夠做很多ftp操作趁窃,例如上傳文件、下載文件急前、下載目錄列表醒陆,創(chuàng)建遠(yuǎn)程目錄等等。
其實(shí)ftp無非就是一個文件流的讀寫操作而已裆针,NSInputStream 和?NSOutputStream 這兩個操作而已刨摩。
>>1、NSInputStream世吨,文件輸入流?
NSInputStream *inputStream = [[NSInputStream alloc] initWithFileAtPath:path]; 此處的path 為文件地址澡刹,通過該地址獲取一個二進(jìn)制文件信息
inputStream.delegate = self;????????//// 設(shè)置代理
? ? [inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; ? ? ? ?//// 加入到對應(yīng)的runloop中
? ? [inputStream open]; ? ? ? ?//// 打開文件流
//// 對應(yīng)的回調(diào)方法
- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode {
//// NSStreamEvent 是回調(diào)的類型判斷。NSStreamEventOpenCompleted 表示鏈接成功
///?NSStreamEventHasBytesAvailable ?讀取數(shù)據(jù)
????????????uint8_t buf[1024];
? ? ? ? ? ? unsigned int len = 0;
? ? ? ? ? ? len = (int)[(NSInputStream *)aStream read:buf maxLength:1024];? // 讀取數(shù)據(jù)
- (NSInteger)read:(uint8_t *)buffer maxLength:(NSUInteger)len; /// 這個方法返回實(shí)際讀取的大小
????????????[inputData appendBytes:(const void *)buf length:len];
/// 到此處即可以把數(shù)據(jù)讀取到?inputData 中
/// ?NSStreamEventEndEncountered 讀取完成耘婚,罢浇,讀取完成后需要移除操作文件流
????????????[aStream close];
? ? ? ? ? ? [aStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
? ? ? ? ? ? aStream = nil;
}
>>2、NSOutputStream沐祷,文件輸出流?
????NSURL *url = [NSURL URLWithString:@"ftp://202.105.45.22/defaultPath/testPath/"];
? ? NSString *account =@"testUsername";
? ? NSString *password =@"testPassword";
NSOutputStream *outputStream = CFBridgingRelease(CFWriteStreamCreateWithFTPURL(NULL,(__bridge CFURLRef) url));
[outputStream setProperty:account forKey:(NSString *)kCFStreamPropertyFTPUserName]; ? ?????/// 設(shè)置 username
? ? [outputStream setProperty:password forKey:(NSString *)kCFStreamPropertyFTPPassword]; ? ? ? ?/// 設(shè)置 password
[outputStream setProperty:kCFBooleanFalse forKey:(NSString *)kCFStreamPropertyFTPAttemptPersistentConnection]; ??/// 保證多次鏈接可實(shí)現(xiàn)
[outputStream setProperty:kCFBooleanFalse forKey:(NSString *)kCFStreamPropertyFTPUsePassiveMode]; ?//設(shè)置鏈接模式(主動嚷闭、被動)(默認(rèn)被動)
/// 設(shè)置代理,添加到對應(yīng)的runloop 赖临,打開
outputStream.delegate = self;
? ? [outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
? ? [outputStream open];
/// 然后待代理回調(diào)中 的?NSStreamEventHasSpaceAvailable下面實(shí)現(xiàn) 直到回掉?NSStreamEventEndEncountered 表示操作完成
????????????uint8_t *readBytes = (uint8_t *)[inputData mutableBytes];
? ? ? ? ? ? readBytes += byteIndex;
? ? ? ? ? ? int data_len = (int)[inputData length];
? ? ? ? ? ? unsigned int len = (data_len - byteIndex >= 1024) ? 1024 : (data_len - byteIndex);
? ? ? ? ? ? uint8_t buf[len];
? ? ? ? ? ? (void)memcpy(buf, readBytes, len);
? ? ? ? ? ? len = (int)[(NSOutputStream *)aStream write:(const uint8_t *)buf maxLength:len];
///?- (NSInteger)write:(const uint8_t *)buffer maxLength:(NSUInteger)len; 這個方法返回實(shí)際寫入多少數(shù)據(jù)
? ? ? ? ? ? if (len == -1) { ?
?????????????????????NSLog(@"寫入錯誤0獭!K急胜蛉!");
? ? ? ? ? ? } else if (len == 0){ ?
????????????????????NSLog(@"寫入完成"); ?
????????????}
? ? ? ? ? ? byteIndex += len;
其實(shí)有一個很好的開源框架挠进,(?FTPManager?)色乾,使用很簡單。
下面直接附上代碼
//初始化文件傳輸管理
- (void)initFTPMgr {
? ? ? ? username = @"appftp";
? ? ? ? password = @"Appftp123";
? ? ? ? hostname = @"101.101.101.101";
? ? ? ? self.requestsManager = [[GRRequestsManager alloc] initWithHostname:hostname ?user:username password:password];
//設(shè)置代理
?? ? ? ?self.requestsManager.delegate = self;
}
//創(chuàng)建圖片文件夾
- (void)createImagePathWithPath {
? ? //創(chuàng)建image文件夾
? ? NSString *imageDir = [NSString stringWithFormat:@"/%@/%@/image",self.baseFileDir,self.baseDateStr];
? ? [self.requestsManager addRequestForCreateDirectoryAtPath:imageDir];
? ? [self.requestsManager startProcessingRequests];
? ? NSLog(@"圖片文件夾路徑 %@",imageDir);
}
//準(zhǔn)備上傳文件
- (void)uploadImageWithPath:(NSURL *)url {
? ? NSString *pathExtension = [url pathExtension];
? ? self.uploadName = [NSString stringWithFormat:@"%@.%@",self.guidStr,pathExtension];
//本地文件路徑
?NSString *path = url.path;
//服務(wù)器文件路徑
? ? NSString *toPath = [NSString stringWithFormat:@"%@/%@/image/%@",self.baseFileDir,self.baseDateStr,self.uploadName];
? ? NSLog(@"path = %@ \n toPath = %@",path,toPath);
? ? NSData *data = [NSData dataWithContentsOfFile:path];
? ? NSLog(@"%ld",data.length);
? ? if (data.length > 0) {
//執(zhí)行上傳文件
? ? ? ? [self.requestsManager addRequestForUploadFileAtLocalPath:path toRemotePath:toPath];
? ? ? ? [self.requestsManager startProcessingRequests];
? ? }
}
#pragma mark -- GRRequestsManagerDelegate ? ?//代理方法
// 完成回調(diào)
- (void)requestsManager:(id)requestsManager didCompleteUploadRequest:(id)request
{
? ? //請求工作流接口
? ? [self requestsUploadSuccess];
? ? NSLog(@"requestsManager:didCompleteUploadRequest:");
}
/** 進(jìn)度條回傳 */
- (void)requestsManager:(id)requestsManager didCompletePercent:(float)percent forRequest:(id)request
{
? ? if (self.uploadProgress) {
? ? ? ? self.uploadProgress(percent);
? ? }
}
//失敗回調(diào)
- (void)requestsManager:(id)requestsManager didFailWritingFileAtPath:(NSString *)path forRequest:(id)request error:(NSError *)error
{
? ? NSLog(@"requestsManager:didFailWritingFileAtPath:forRequest:error: \n %@", error);
}
- (void)requestsManager:(id)requestsManager didFailRequest:(id)request withError:(NSError *)error
{
? ? NSLog(@"requestsManager:didFailRequest:withError: \n %@", error);
}
最后附上我感覺好用的FTP庫(?KLFTPHeper?)