? ? 由于公司最近項(xiàng)目中 有個(gè)需求是要把你掃描獲得的圖片上傳到ftp服務(wù)器 ,建于以前做的基本都是通過(guò)http 上傳至服務(wù)器加上以前沒有做過(guò)上傳至ftp服務(wù)器并级,所以在此總結(jié)一下網(wǎng)上百度到的基本處理方法拂檩。
? ? ?先說(shuō)一下基本簡(jiǎn)介,在iOS端的ftp上傳使用的是CFNetWork框架嘲碧,它處于核心服務(wù)框架中,提供了一個(gè)抽象化的網(wǎng)絡(luò)協(xié)議庫(kù)稻励。使用CFNetWork框架中的CFFTPStream類提供的API能夠做很多ftp操作,例如上傳文件愈涩、下載文件望抽、下載目錄列表,創(chuàng)建遠(yuǎn)程目錄等等履婉。
? ? 接下來(lái)廢話不多說(shuō) 直接上代碼
1.首先項(xiàng)目中倒入CFNetwork.framework 框架 ?并且遵循<NSStreamDelegate>?
2.接下來(lái)定義一個(gè)枚舉
enum {
kSendBufferSize = 32768
};
3.@interface里定義屬性
{
uint8_t _buffer[kSendBufferSize];
}
//創(chuàng)建內(nèi)部變量
@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;
}
//寫個(gè)方法用于上傳照片
- (void)uploadFacePicturesImage{
NSURL *url;//ftp服務(wù)器地址
?NSString *filePath;//圖片地址
NSString *account;//賬號(hào)
NSString *password;//密碼
CFWriteStreamRef ftpStream;
//獲得輸入
NSString *urlStr = [NSString stringWithFormat:@"你要上傳的ftp服務(wù)器地址“];
url = [NSURL URLWithString:urlStr];
filePath = [[NSBundle mainBundle] pathForResource:@"h" ofType:@"png"];//注:這里的filepath 是從bunndle中取得煤篙。我在項(xiàng)目里是把之前掃描獲取到的圖片保存在了沙盒中 從沙盒中讀取的路徑 同時(shí)也可以寫從本地相冊(cè)中獲取。就不一一列舉了 ?看你實(shí)際的需求
account = @"你要上傳的ftp服務(wù)器用戶名";
password = @"你要上傳的ftp服務(wù)器密碼";
//添加后綴(文件名稱)
url = [NSMakeCollectable(CFURLCreateCopyAppendingPathComponent(NULL, (CFURLRef) url, (CFStringRef) [filePath lastPathComponent], false)) autorelease];
//讀取文件毁腿,轉(zhuǎn)化為輸入流
self.fileStream = [NSInputStream inputStreamWithFileAtPath:filePath];
[self.fileStream open];
//為url開啟CFFTPStream輸出流
ftpStream = CFWriteStreamCreateWithFTPURL(NULL, (CFURLRef) url);
self.networkStream = (NSOutputStream *) ftpStream;
//設(shè)置ftp賬號(hào)密碼
[self.networkStream setProperty:account forKey:(id)kCFStreamPropertyFTPUserName];
[self.networkStream setProperty:password forKey:(id)kCFStreamPropertyFTPPassword];
//設(shè)置networkStream流的代理辑奈,任何關(guān)于networkStream的事件發(fā)生都會(huì)調(diào)用代理方法
self.networkStream.delegate = self;
//設(shè)置runloop
[self.networkStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[self.networkStream open];
//完成釋放鏈接
CFRelease(ftpStream);
}
5. 設(shè)置回調(diào)方法
#pragma mark 回調(diào)方法
- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode
{
//aStream 即為設(shè)置為代理的networkStream
switch (eventCode) {
case NSStreamEventOpenCompleted: {
NSLog(@"NSStreamEventOpenCompleted");
} break;
case NSStreamEventHasBytesAvailable: {
NSLog(@"NSStreamEventHasBytesAvailable");
assert(NO);? ? // 在上傳的時(shí)候不會(huì)調(diào)用
} 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) {
//讀取文件錯(cuò)誤
[self _stopSendWithStatus:@"讀取文件錯(cuò)誤"];
} else if (bytesRead == 0) {
//文件讀取完成 上傳完成
[self _stopSendWithStatus:nil];
} else {
self.bufferOffset = 0;
self.bufferLimit? = bytesRead;
}
}
if (self.bufferOffset != self.bufferLimit) {
//寫入數(shù)據(jù)
NSInteger bytesWritten;//bytesWritten為成功寫入的數(shù)據(jù)
bytesWritten = [self.networkStream write:&self.buffer[self.bufferOffset] maxLength:self.bufferLimit - self.bufferOffset];
assert(bytesWritten != 0);
if (bytesWritten == -1) {
[self _stopSendWithStatus:@"網(wǎng)絡(luò)寫入錯(cuò)誤"];
} else {
self.bufferOffset += bytesWritten;
}
}
} break;
case NSStreamEventErrorOccurred: {
[self _stopSendWithStatus:@"Stream打開錯(cuò)誤"];
assert(NO);
} break;
case NSStreamEventEndEncountered: {
// 忽略
} break;
default: {
assert(NO);
} break;
}
}
//結(jié)果處理
- (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上傳圖片了 上述回調(diào)方法說(shuō)明:bytesWritten為實(shí)際寫入的數(shù)據(jù)量,雖然緩沖區(qū)大小是固定的值已烤,但每次寫入并不一定是充滿緩沖區(qū)鸠窗,可以看到NSLog的輸出值。(上傳圖片大小為428492字節(jié)胯究,約430k)稍计。
首先是NSStreamEventOpenCompleted打開事件完成的回調(diào),然后不斷發(fā)送NSStreamEventHasSpaceAvailable消息完成整個(gè)上傳過(guò)程裕循。
可以看到在傳輸?shù)臅r(shí)候臣嚣,bufferOffset并不是每次都是32768,所以self.bufferOffset!= self.bufferLimit是一個(gè)續(xù)傳上次未完數(shù)據(jù)的過(guò)程剥哑,而當(dāng)self.bufferOffset = self.bufferLimit時(shí)硅则,即上次的32768已經(jīng)傳完了,此時(shí)將bufferOffset重新設(shè)置為0星持。
另外 如果需要在ftp上做一些其他處理 可以github上 搜索GoldRaccoon作為參考 附上地址https://github.com/albertodebortoli/GoldRaccoon
附上上述步驟的一些圖片 以便更加詳細(xì)觀看
接下來(lái) 寫一下原先用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];
//結(jié)束符 AaB03x--
NSString *endMPboundary=[[NSString alloc]initWithFormat:@"%@--",MPboundary];
NSMutableString *body=[[NSMutableString alloc]init];
//參數(shù)的集合的所有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"];
//聲明結(jié)束符:--AaB03x-
NSString *end=[[NSString alloc]initWithFormat:@"\r\n%@",endMPboundary];
//聲明myRequestData,用來(lái)放入http body
NSMutableData *myRequestData=[NSMutableData data];
//將body字符串轉(zhuǎn)化為UTF8格式的二進(jìn)制
[myRequestData appendData:[body dataUsingEncoding:NSUTF8StringEncoding]];
//將image的data加入
[myRequestData appendData:data];
//加入結(jié)束符--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"]);
}
}
}];
}