對于 NSInputStream 和 NSOutputStream 一直沒怎么搞清楚,今天抽一些時間在此記錄一下!
NSInputStream 與 NSOutputStream 都繼承于 NSStream, NSStream 是一個抽象的基類, 規(guī)定了Stream共有的一些行為…
什么是Stream
Stream翻譯成為流,它是對我們讀寫文件的一個抽象。 你可以這樣想象,當你讀文件和寫文件的時候,文件的內(nèi)容就像水流一樣嘩嘩的 像你流過來或者流給別人,這樣豈不是很爽。 而Stream就幫我們做了這樣的事情, 實際上,它是把文件的內(nèi)容,一小段一小段的讀出或 寫入,來到達這樣的效果
NSStream
NSStream 是Cocoa平臺下對流這個概念的實現(xiàn)類, NSInputStream 和 NSOutputStream 則是它的兩個子類,分別對應了讀文件和 寫文件。
NSInputStream
NSInputStream 對應的是讀文件,所以要記住它是要將文件的內(nèi)容讀到內(nèi)存(你聲明的一段buffer)里, 下面一段是測試代碼
-(void)doTestInputStream{NSString*path=@"/Users/usr/Desktop/stream.txt";NSInputStream*readStream=[[NSInputStreamalloc]initWithFileAtPath:path];[readStreamsetDelegate:self];[readStreamscheduleInRunLoop:[NSRunLoopcurrentRunLoop]forMode:NSRunLoopCommonModes];[readStreamopen];//調(diào)用open開始讀文件}-(void)stream:(NSStream*)aStreamhandleEvent:(NSStreamEvent)eventCode{switch(eventCode){caseNSStreamEventHasBytesAvailable:{uint8_tbuf[1024];NSInputStream*reads=(NSInputStream*)aStream;NSIntegerblength=[readsread:bufmaxLength:sizeof(buf)];//把流的數(shù)據(jù)放入bufferNSData*data=[NSDatadataWithBytes:(void*)buflength:blength];NSString*string=[[NSStringalloc]initWithData:dataencoding:NSUTF8StringEncoding];NSLog(@"%@",string);}break;//錯誤和無事件處理caseNSStreamEventErrorOccurred:{}break;caseNSStreamEventNone:break;//打開完成caseNSStreamEventOpenCompleted:{NSLog(@"NSStreamEventOpenCompleted");}break;default:break;}}@end
NSOutputStream
NSOutputStream 對應的是寫文件,它是要將已存在的內(nèi)存(buffer)里的數(shù)據(jù)寫入文件, 下面同樣一段是測試代碼
-(NSData*)dataWillWrite{staticNSData*data=nil;staticdispatch_once_tonceToken;dispatch_once(&onceToken,^{data=[NSDatadataWithContentsOfFile:@"/Users/usr/Desktop/stream.txt"];});returndata;}-(void)doTestOutputStream{NSString*path=@"/Users/usr/Desktop/stream-write.txt";NSOutputStream*writeStream=[[NSOutputStreamalloc]initToFileAtPath:pathappend:YES];[writeStreamsetDelegate:self];[writeStreamscheduleInRunLoop:[NSRunLoopcurrentRunLoop]forMode:NSRunLoopCommonModes];[writeStreamopen];}-(void)stream:(NSStream*)aStreamhandleEvent:(NSStreamEvent)eventCode{switch(eventCode){caseNSStreamEventHasSpaceAvailable:{NSIntegerbufSize=5;uint8_tbuf[bufSize];if(self.location+bufSize>[selfdataWillWrite].length){[[selfdataWillWrite]getBytes:bufrange:NSMakeRange(self.location,self.location+bufSize-[selfdataWillWrite].length)];}else{[[selfdataWillWrite]getBytes:bufrange:NSMakeRange(self.location,bufSize)];}NSOutputStream*writeStream=(NSOutputStream*)aStream;[writeStreamwrite:bufmaxLength:sizeof(buf)];//把buffer里的數(shù)據(jù),寫入文件self.location+=bufSize;if(self.location>=[[selfdataWillWrite]length]){//寫完后關(guān)閉流[aStreamclose];}}break;caseNSStreamEventEndEncountered:{[aStreamclose];}break;//錯誤和無事件處理caseNSStreamEventErrorOccurred:{}break;caseNSStreamEventNone:break;//打開完成caseNSStreamEventOpenCompleted:{NSLog(@"NSStreamEventOpenCompleted");}break;default:break;}}
用途
NSInputStream 和 NSOutputStream 常用與網(wǎng)絡傳輸中,比如要將一個很大的文件傳送給服務器,那么NSInputStream這時候是 很好的選擇, 我們可以查看到 NSURLRequest 有一個屬性叫HTTPBodyStream, 這時只要設置好一個NSInputStream的實例就可以 了,最大的好處就是可以節(jié)省我們很多的內(nèi)存。
另外要說明的是,NSInputStream 和 NSOutputStream其實是對 CoreFoundation 層對應的CFReadStreamRef 和 CFWriteStreamRef 的高層抽象。在使用CFNetwork時,常常會使用到CFReadStreamRef 與 CFWriteStreamRef。 下面是一段相關(guān)代碼
// Keep a reference to self to use for controller callbacks//CFStreamClientContextctx={0,(__bridgevoid*)(self),NULL,NULL,NULL};// Get callbacks for stream data, stream end, and any errors//CFOptionFlagsregisteredEvents=(kCFStreamEventHasBytesAvailable|kCFStreamEventEndEncountered|kCFStreamEventErrorOccurred);// Create a read-only socket//CFReadStreamRefreadStream;CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault,(__bridgeCFStringRef)host,(UInt32)port,&readStream,NULL);// Schedule the stream on the run loop to enable callbacks//if(CFReadStreamSetClient(readStream,registeredEvents,socketCallback,&ctx)){CFReadStreamScheduleWithRunLoop(readStream,CFRunLoopGetCurrent(),kCFRunLoopCommonModes);}else{[selfnetworkFailedWithErrorMessage:@"Failed to assign callback method"];return;}// Open the stream for reading//if(CFReadStreamOpen(readStream)==NO){[selfnetworkFailedWithErrorMessage:@"Failed to open read stream"];return;}CFErrorReferror=CFReadStreamCopyError(readStream);if(error!=NULL){if(CFErrorGetCode(error)!=0){NSString*errorInfo=[NSStringstringWithFormat:@"Failed to connect stream; error '%@' (code %ld)",(__bridgeNSString*)CFErrorGetDomain(error),CFErrorGetCode(error)];[selfnetworkFailedWithErrorMessage:errorInfo];}CFRelease(error);return;}