由于公司最近项目中 有个需求是要把你扫描获得的图片上传到ftp服务器 ,建于以前做的基本都是通过http 上传至服务器加上以前没有做过上传至ftp服务器,所以在此总结一下网上百度到的基本处理方法。
先说一下基本简介,在iOS端的ftp上传使用的是CFNetWork框架,它处于核心服务框架中,提供了一个抽象化的网络协议库。使用CFNetWork框架中的CFFTPStream类提供的API能够做很多ftp操作,例如上传文件、下载文件、下载目录列表,创建远程目录等等。
接下来废话不多说 直接上代码
1.首先项目中倒入CFNetwork.framework 框架 并且遵循<NSStreamDelegate>
2.接下来定义一个枚举
enum {
kSendBufferSize = 32768
};
3.@interface里定义属性
{
uint8_t _buffer[kSendBufferSize];
}
//创建内部变量
@property (nonatomic, retain) NSOutputStream * networkStream;
@property (nonatomic, retain) NSInputStream * fileStream;
@property (nonatomic, readonly) uint8_t * buffer;
@property (nonatomic, assign) size_t bufferOffset;
@property (nonatomic, assign) size_t bufferLimit;
4.@implementation里
- (uint8_t *)buffer
{
return self->_buffer;
}
//写个方法用于上传照片
- (void)uploadFacePicturesImage{
NSURL *url;//ftp服务器地址
NSString *filePath;//图片地址
NSString *account;//账号
NSString *password;//密码
CFWriteStreamRef ftpStream;
//获得输入
NSString *urlStr = [NSString stringWithFormat:@"你要上传的ftp服务器地址“];
url = [NSURL URLWithString:urlStr];
filePath = [[NSBundle mainBundle] pathForResource:@"h" ofType:@"png"];//注:这里的filepath 是从bunndle中取得。我在项目里是把之前扫描获取到的图片保存在了沙盒中 从沙盒中读取的路径 同时也可以写从本地相册中获取。就不一一列举了 看你实际的需求
account = @"你要上传的ftp服务器用户名";
password = @"你要上传的ftp服务器密码";
//添加后缀(文件名称)
url = [NSMakeCollectable(CFURLCreateCopyAppendingPathComponent(NULL, (CFURLRef) url, (CFStringRef) [filePath lastPathComponent], false)) autorelease];
//读取文件,转化为输入流
self.fileStream = [NSInputStream inputStreamWithFileAtPath:filePath];
[self.fileStream open];
//为url开启CFFTPStream输出流
ftpStream = CFWriteStreamCreateWithFTPURL(NULL, (CFURLRef) url);
self.networkStream = (NSOutputStream *) ftpStream;
//设置ftp账号密码
[self.networkStream setProperty:account forKey:(id)kCFStreamPropertyFTPUserName];
[self.networkStream setProperty:password forKey:(id)kCFStreamPropertyFTPPassword];
//设置networkStream流的代理,任何关于networkStream的事件发生都会调用代理方法
self.networkStream.delegate = self;
//设置runloop
[self.networkStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[self.networkStream open];
//完成释放链接
CFRelease(ftpStream);
}
5. 设置回调方法
#pragma mark 回调方法
- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode
{
//aStream 即为设置为代理的networkStream
switch (eventCode) {
case NSStreamEventOpenCompleted: {
NSLog(@"NSStreamEventOpenCompleted");
} break;
case NSStreamEventHasBytesAvailable: {
NSLog(@"NSStreamEventHasBytesAvailable");
assert(NO); // 在上传的时候不会调用
} break;
case NSStreamEventHasSpaceAvailable: {
NSLog(@"NSStreamEventHasSpaceAvailable");
NSLog(@"bufferOffset is %zd",self.bufferOffset);
NSLog(@"bufferLimit is %zu",self.bufferLimit);
if (self.bufferOffset == self.bufferLimit) {
NSInteger bytesRead;
bytesRead = [self.fileStream read:self.buffer maxLength:kSendBufferSize];
if (bytesRead == -1) {
//读取文件错误
[self _stopSendWithStatus:@"读取文件错误"];
} else if (bytesRead == 0) {
//文件读取完成 上传完成
[self _stopSendWithStatus:nil];
} else {
self.bufferOffset = 0;
self.bufferLimit = bytesRead;
}
}
if (self.bufferOffset != self.bufferLimit) {
//写入数据
NSInteger bytesWritten;//bytesWritten为成功写入的数据
bytesWritten = [self.networkStream write:&self.buffer[self.bufferOffset] maxLength:self.bufferLimit - self.bufferOffset];
assert(bytesWritten != 0);
if (bytesWritten == -1) {
[self _stopSendWithStatus:@"网络写入错误"];
} else {
self.bufferOffset += bytesWritten;
}
}
} break;
case NSStreamEventErrorOccurred: {
[self _stopSendWithStatus:@"Stream打开错误"];
assert(NO);
} break;
case NSStreamEventEndEncountered: {
// 忽略
} break;
default: {
assert(NO);
} break;
}
}
//结果处理
- (void)_stopSendWithStatus:(NSString *)statusString
{
if (self.networkStream != nil) {
[self.networkStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
self.networkStream.delegate = nil;
[self.networkStream close];
self.networkStream = nil;
}
if (self.fileStream != nil) {
[self.fileStream close];
self.fileStream = nil;
}
[self _sendDidStopWithStatus:statusString];
}
- (void)_sendDidStopWithStatus:(NSString *)statusString
{
if (statusString == nil) {
statusString = @"上传成功";
}
}
按着以上操作的话就可以完成ftp上传图片了 上述回调方法说明:bytesWritten为实际写入的数据量,虽然缓冲区大小是固定的值,但每次写入并不一定是充满缓冲区,可以看到NSLog的输出值。(上传图片大小为428492字节,约430k)。
首先是NSStreamEventOpenCompleted打开事件完成的回调,然后不断发送NSStreamEventHasSpaceAvailable消息完成整个上传过程。
可以看到在传输的时候,bufferOffset并不是每次都是32768,所以self.bufferOffset!= self.bufferLimit是一个续传上次未完数据的过程,而当self.bufferOffset = self.bufferLimit时,即上次的32768已经传完了,此时将bufferOffset重新设置为0。
另外 如果需要在ftp上做一些其他处理 可以github上 搜索GoldRaccoon作为参考 附上地址https://github.com/albertodebortoli/GoldRaccoon
附上上述步骤的一些图片 以便更加详细观看



接下来 写一下原先用NSURLConnection 上传图片
-(void)uploadPicturesImage:(UIImage* )image nsNo:(NSString* )nsNo{
NSData* data = UIImageJPEGRepresentation(image, 0.01);
NSString *TWITTERFON_FORM_BOUNDARY = @"AaB03x";
//分界线 --AaB03x
NSString *MPboundary=[[NSString alloc]initWithFormat:@"--%@",TWITTERFON_FORM_BOUNDARY];
//结束符 AaB03x--
NSString *endMPboundary=[[NSString alloc]initWithFormat:@"%@--",MPboundary];
NSMutableString *body=[[NSMutableString alloc]init];
//参数的集合的所有key的集合
[body appendFormat:@"%@\r\n",MPboundary];
//声明pic字段,文件名为boris.png
[body appendFormat:@"Content-Disposition:form-data;name=%@;filename=%@.jpg\r\n",@"名字",@"名字"];
//声明上传文件的格式
[body appendFormat:@"Content-Type:application/octet-stream\r\n\r\n"];
//声明结束符:--AaB03x-
NSString *end=[[NSString alloc]initWithFormat:@"\r\n%@",endMPboundary];
//声明myRequestData,用来放入http body
NSMutableData *myRequestData=[NSMutableData data];
//将body字符串转化为UTF8格式的二进制
[myRequestData appendData:[body dataUsingEncoding:NSUTF8StringEncoding]];
//将image的data加入
[myRequestData appendData:data];
//加入结束符--AaB03x--
[myRequestData appendData:[end dataUsingEncoding:NSUTF8StringEncoding]];
NSString* urlIp = [PublicFunction getHttpUrlIp];
NSString *phone = [[NSUserDefaults standardUserDefaults] objectForKey:USER_NAME];
NSString *urlString = [NSString stringWithFormat:@"上传url“];
urlString = [urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSLog(@"上传图片:%@",urlString);
NSURL *url = [[NSURL alloc] initWithString:urlString];
assert(url != nil);
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
[request setTimeoutInterval:50];
NSString *contentType = [NSString stringWithFormat:@"multipart/form-data;boundary=%@",TWITTERFON_FORM_BOUNDARY];
[request addValue:contentType forHTTPHeaderField:@"Content-Type"];
[request setHTTPMethod:@"POST"];
[request setHTTPBody:myRequestData];
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
if (connectionError == nil) {
NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil];
NSLog(@"%@",dic);
NSString *code = [dic objectForKey:@"code"];
if ([code isEqualToString:@"00"]) {
NSLog(@"上传成功-----msg--%@",[dic objectForKey:@"content"]);
}else {
NSLog(@"上传失败-----msg--%@",[dic objectForKey:@"content"]);
}
}
}];
}
网友评论