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

来源:互联网 发布:2016网络流行语字母 编辑:程序博客网 时间:2024/06/05 19:43

最底层的 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的实例就可以 了,最大的好处就是可以节省我们很多的内存。

  1. 上传文件事件:

`- (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
「 

1 0
原创粉丝点击