最底层的 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
「
」