您的位置:首页 > 移动开发 > IOS开发

iOS--NSStreamDelegate 的协议来实现 CFNetwork 中的回调函数的作用实现ftp上传下载功能

2016-11-29 11:26 357 查看
最底层的 socket 和Core Foundation层的 CFNetwork,位于 Cocoa 中的 NSStream。NSStream 其实只是用 Objective-C 对 CFNetwork 的简单封装,它使用名为 NSStreamDelegate 的协议来实现 CFNetwork 中的回调函数的作用,同样,runloop 也与 NSStream 结合的很好。NSStream 有两个实体类:NSInputStream 和 NSOutputStream,分别对应 CFNetwork 中的 CFReadStream 和 CFWriteStream 的高层抽象。在使用CFNetwork时,常常会使用到CFReadStreamRef 与 CFWriteStreamRef。

enum {

kSendBufferSize = 32768

};

在.h文件中实现代理 NSStreamDelegate协议。

{

uint8_t _buffer[kSendBufferSize];

}

在.m文件中。

@property (nonatomic, readonly) BOOL isSending;

@property (nonatomic, retain) NSOutputStream * networkStream;/写文件,它是要将已存在的内存(buffer)里的数据写入文件,

@property (nonatomic, retain) NSInputStream * fileStream;//读文件,所以要记住它是要将文件的内容读到内存(你声明的一段buffer)里,

@property (nonatomic, readonly) uint8_t * buffer;

@property (nonatomic, assign) size_t bufferOffset;

@property (nonatomic, assign) size_t bufferLimit;

NSInputStream 和 NSOutputStream 常用与网络传输中,比如要将一个很大的文件传送给服务器,那么NSInputStream这时候是 很好的选择, 我们可以查看到 NSURLRequest 有一个属性叫HTTPBodyStream, 这时只要设置好一个NSInputStream的实例就可以 了,最大的好处就是可以节省我们很多的内存。

上传文件事件:

`- (IBAction)sendAction:(id)sender {

NSURL *url;//ftp服务器地址

NSString *filePath;//图片地址

CFWriteStreamRef ftpStream;//获得输入

url = [NSURL URLWithString:[NSString stringWithFormat:@”ftp://…………………..”]];

//

filePath = @”/Users/guest/Desktop/844be47c939c524cebb03b72ae75bdbd.jpg”;

account = @“”;

password = @“”;

//添加后缀(文件名称)

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:URL_FTP_UserName forKey:(id)kCFStreamPropertyFTPUserName];

[self.networkStream setProperty:URL_FTP_PassWord forKey:(id)kCFStreamPropertyFTPPassword];

//设置networkStream流的代理,任何关于networkStream的事件发生都会调用代理方法

self.networkStream.delegate = self;

//设置runloop

[self.networkStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];

[self.networkStream open];

//完成释放链接

CFRelease(ftpStream);

}

2.下载事件:

-(void)downloadRemoteFile:(NSString )fileurl localFileName:(NSString )localname{

CFReadStreamRef ftpStream;

NSURL *urll=nil;

NSString *pth=nil;

NSArray* NSDocumentpaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);

fileurl=[fileurl stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];

localname =[localname stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];

pth =[NSString stringWithFormat:@”%@%@”,URL_FTP_AddressURL,fileurl];

pth=[pth stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];

urll = [NSURL URLWithString:pth];

//读取文件,转化为输入流

self.downloadfileStream = [NSOutputStream outputStreamToFileAtPath: self.filePath append:NO];

[self.downloadfileStream open];

//为url开启CFFTPStream输出流

ftpStream = CFReadStreamCreateWithFTPURL(NULL, (__bridge CFURLRef) urll);

self.dataStream = (__bridge NSInputStream *) ftpStream

if (ftpStream == nil) {

[self.dataStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];

self.dataStream.delegate = nil;

[self.dataStream close];

self.dataStream = nil;

[self.downloadfileStream close];

self.downloadfileStream = nil;

}else{

assert(ftpStream != NULL);

//设置ftp账号密码

[self.dataStream setProperty:URL_FTP_UserName forKey:(id)kCFStreamPropertyFTPUserName];

[self.dataStream setProperty:URL_FTP_PassWord forKey:(id)kCFStreamPropertyFTPPassword];

// 设置代理

self.dataStream.delegate = self;

// 启动循环

[self.dataStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];

[self.dataStream open];

}

CFRelease(ftpStream);

}

最重要的实现代理方法。

pragma mark 回调方法

(void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode

{

//aStream 即为设置为代理的networkStream

switch (eventCode) {

case NSStreamEventOpenCompleted: {

NSLog(@”NSStreamEventOpenCompleted”);

} break;

case NSStreamEventHasBytesAvailable: {

NSInteger bytesRead;

uint8_t buffer[32768];//缓冲区的大小 32768可以设置,uint8_t为一个字节大小的无符号int类型

// 读取数据

bytesRead = [self.dataStream read:buffer maxLength:sizeof(buffer)];

if (bytesRead == -1) {

[self _stopSendWithStatus:@”读取网络数据出错”];

} else if (bytesRead == 0) {

//下载成功

[self _stopSendWithStatus:@”1”];

} else {

NSInteger bytesWritten;//实际写入数据

NSInteger bytesWrittenSoFar;//当前数据写入位

// 写入文件

bytesWrittenSoFar = 0;

do {

bytesWritten = [self.downloadfileStream write:&buffer[bytesWrittenSoFar] maxLength:bytesRead - bytesWrittenSoFar];

assert(bytesWritten != 0);

if (bytesWritten == -1) {

[self _stopSendWithStatus:@”文件写入出错”];

assert(NO);

break;

} else {

bytesWrittenSoFar += bytesWritten;

}

} while (bytesWrittenSoFar != bytesRead);

}

} break;

case NSStreamEventHasSpaceAvailable: {

} break;

case NSStreamEventErrorOccurred: {

[self _stopSendWithStatus:@”Stream打开错误,打开出错,请检查路径”];

} break;

case NSStreamEventEndEncountered: {

// 忽略

} break;

default: {

assert(NO);

} break;

}

}

这样就可以完成上传和下载的过程了。

//结果处理

- (void)_stopSendWithStatus:(NSString *)statusString

「 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: