在日常开发中,我们都在用http(s) 来进行网络传输的,上传下载等任务的,前段时间听说要用ftp来上传资源,当时还是一脸懵逼的。后来东拼西凑的算是勉强搞定了。
在iOS端的ftp上传使用的是CFNetWork框架,它处于核心服务框架中,提供了一个抽象化的网络协议库。使用CFNetWork框架中的CFFTPStream类提供的API能够做很多ftp操作,例如上传文件、下载文件、下载目录列表,创建远程目录等等。
其实ftp无非就是一个文件流的读写操作而已,NSInputStream 和 NSOutputStream 这两个操作而已。
>>1、NSInputStream,文件输入流
NSInputStream *inputStream = [[NSInputStream alloc] initWithFileAtPath:path]; 此处的path 为文件地址,通过该地址获取一个二进制文件信息
inputStream.delegate = self; //// 设置代理
[inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; //// 加入到对应的runloop中
[inputStream open]; //// 打开文件流
//// 对应的回调方法
- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode {
//// NSStreamEvent 是回调的类型判断。NSStreamEventOpenCompleted 表示链接成功
/// NSStreamEventHasBytesAvailable 读取数据
uint8_t buf[1024];
unsigned int len = 0;
len = (int)[(NSInputStream *)aStream read:buf maxLength:1024]; // 读取数据
- (NSInteger)read:(uint8_t *)buffer maxLength:(NSUInteger)len; /// 这个方法返回实际读取的大小
[inputData appendBytes:(const void *)buf length:len];
/// 到此处即可以把数据读取到 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]; /// 设置 username
[outputStream setProperty:password forKey:(NSString *)kCFStreamPropertyFTPPassword]; /// 设置 password
[outputStream setProperty:kCFBooleanFalse forKey:(NSString *)kCFStreamPropertyFTPAttemptPersistentConnection]; /// 保证多次链接可实现
[outputStream setProperty:kCFBooleanFalse forKey:(NSString *)kCFStreamPropertyFTPUsePassiveMode]; //设置链接模式(主动、被动)(默认被动)
/// 设置代理,添加到对应的runloop ,打开
outputStream.delegate = self;
[outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[outputStream open];
/// 然后待代理回调中 的 NSStreamEventHasSpaceAvailable下面实现 直到回掉 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; 这个方法返回实际写入多少数据
if (len == -1) {
NSLog(@"写入错误!!!!");
} else if (len == 0){
NSLog(@"写入完成");
}
byteIndex += len;
其实有一个很好的开源框架,( FTPManager ),使用很简单。
下面直接附上代码
//初始化文件传输管理
- (void)initFTPMgr {
username = @"appftp";
password = @"Appftp123";
hostname = @"101.101.101.101";
self.requestsManager = [[GRRequestsManager alloc] initWithHostname:hostname user:username password:password];
//设置代理
self.requestsManager.delegate = self;
}
//创建图片文件夹
- (void)createImagePathWithPath {
//创建image文件夹
NSString *imageDir = [NSString stringWithFormat:@"/%@/%@/image",self.baseFileDir,self.baseDateStr];
[self.requestsManager addRequestForCreateDirectoryAtPath:imageDir];
[self.requestsManager startProcessingRequests];
NSLog(@"图片文件夹路径 %@",imageDir);
}
//准备上传文件
- (void)uploadImageWithPath:(NSURL *)url {
NSString *pathExtension = [url pathExtension];
self.uploadName = [NSString stringWithFormat:@"%@.%@",self.guidStr,pathExtension];
//本地文件路径
NSString *path = url.path;
//服务器文件路径
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) {
//执行上传文件
[self.requestsManager addRequestForUploadFileAtLocalPath:path toRemotePath:toPath];
[self.requestsManager startProcessingRequests];
}
}
#pragma mark -- GRRequestsManagerDelegate //代理方法
// 完成回调
- (void)requestsManager:(id)requestsManager didCompleteUploadRequest:(id)request
{
//请求工作流接口
[self requestsUploadSuccess];
NSLog(@"requestsManager:didCompleteUploadRequest:");
}
/** 进度条回传 */
- (void)requestsManager:(id)requestsManager didCompletePercent:(float)percent forRequest:(id)request
{
if (self.uploadProgress) {
self.uploadProgress(percent);
}
}
//失败回调
- (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 )