搜索后我发现只有在服务器断开连接时才会调用事件NsstreamEventEndEncountered.不是如果OutputStream已完成要发送的数据.
StreamStatus始终返回0(连接关闭)或2(连接打开)但从不返回4(写入数据).
由于上面提到的两种方法都没有告诉我有关写入过程的信息,我无法找到确定Stream是否仍在写入的方法,或者它是否已经完成并且我现在可以关闭连接.
经过5天的Googleling并尝试我完全没有想法…任何帮助表示赞赏.谢谢
根据要求编辑添加的代码:
- (voID)startSend:(Nsstring *)filePath{BOol success;NSURL * url;assert(filePath != nil);assert([[NSfileManager defaultManager] fileExistsAtPath:filePath]);assert( [filePath.pathExtension isEqual:@"png"] || [filePath.pathExtension isEqual:@"jpg"] );assert(self.networkStream == nil); // don't tap send twice in a row!assert(self.fileStream == nil); // ditto// First get and check the URL.............// If the URL is bogus,let the user kNow. Otherwise kick off the connection.............if ( ! success) { self.statusLabel.text = @"InvalID URL";} else { // Open a stream for the file we're going to send. We do not open this stream; // NSURLConnection will do it for us. self.fileStream = [NSinputStream inputStreamWithfileAtPath:filePath]; assert(self.fileStream != nil); [self.fileStream open]; // Open a CFFTPStream for the URL. self.networkStream = CFBrIDgingrelease( CFWriteStreamCreateWithFTPURL(NulL,(__brIDge CFURLRef) url) ); assert(self.networkStream != nil); if ([self.usernameText.text length] != 0) { success = [self.networkStream setProperty:self.usernameText.text forKey:(ID)kcfStreamPropertyFTPUsername]; assert(success); success = [self.networkStream setProperty:self.passwordText.text forKey:(ID)kcfStreamPropertyFTPPassword]; assert(success); } self.networkStream.delegate = self; [self.networkStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; ///////******** liNE ADDED BY ME TO disONNECT FROM FTP AFTER CLOSING CONNECTION *********//////////// [self.networkStream setProperty:(ID)kcfBooleanFalse forKey:(ID)kcfStreamPropertyFTPAttemptPersistentConnection]; ///////******** END liNE ADDED BY ME *********//////////// [self.networkStream open]; // Tell the UI we're sending. [self sendDIDStart];}}- (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)stream:(Nsstream *)aStream handleEvent:(NsstreamEvent)eventCode// An Nsstream delegate callback that's called when events happen on our // network stream.{#pragma unused(aStream)assert(aStream == self.networkStream);switch (eventCode) { case NsstreamEventopenCompleted: { [self updateStatus:@"Opened connection"]; } break; case NsstreamEventHasBytesAvailable: { assert(NO); // should never happen for the output stream } break; case NsstreamEventHasspaceAvailable: { [self updateStatus:@"Sending"]; // If we don't have any data buffered,go read the next chunk of data. if (self.bufferOffset == self.bufferlimit) { NSInteger bytesRead; bytesRead = [self.fileStream read:self.buffer maxLength:kSendBufferSize]; if (bytesRead == -1) { [self stopSenDWithStatus:@"file read error"]; } else if (bytesRead == 0) { [self stopSenDWithStatus:nil]; } else { self.bufferOffset = 0; self.bufferlimit = bytesRead; } } // If we're not out of data completely,send the next chunk. if (self.bufferOffset != self.bufferlimit) { NSInteger bytesWritten; bytesWritten = [self.networkStream write:&self.buffer[self.bufferOffset] maxLength:self.bufferlimit - self.bufferOffset]; assert(bytesWritten != 0); if (bytesWritten == -1) { [self stopSenDWithStatus:@"Network write error"]; } else { self.bufferOffset += bytesWritten; } } } break; case NsstreamEventErrorOccurred: { [self stopSenDWithStatus:@"Stream open error"]; } break; case NsstreamEventEndEncountered: { // FOR WHATEVER REASON THIS IS NEVER CALLED!!!! } break; default: { assert(NO); } break;}}解决方法 您的问题可以有两种解释.如果您要问的是“我有一个NSOutputStream并且我已经写完了它,我该如何发出信号?”然后答案就像调用close方法一样简单.
或者,如果您真正说的是“我有一个NSinputStream并且我想知道何时到达流末尾”那么您可以查看hasBytesAvailable或streamStatus == NsstreamStatusAtEnd.
为了您的信息,要实际获取状态NsstreamStatusWriting,您需要在此线程调用write:maxLength:时从另一个线程调用streamStatus方法.
—编辑:代码建议
您永远不会得到通知的原因是输出流永远不会完成(除非它是固定大小的流,而不是FTP流).它是“完成”的输入流,此时您可以关闭输出流.这是你原来问题的答案.
作为进一步的建议,我将跳过运行循环调度和“事件处理”,除了处理输出流上的错误.然后我将读/写代码放入NSOperation子类并将其发送到NSOperationQueue.通过在该队列中保留对NSOperations的引用,您可以轻松取消它们,甚至可以通过添加percentComplete属性来显示进度条.我已经测试了下面的代码并且它有效.用FTP输出流替换我的内存输出流.您会注意到我已经跳过了验证,您当然应该保留这些验证.它们应该在NSOperation之外完成,以便更容易查询用户.
@interface NSSendfileOperation : NSOperation<NsstreamDelegate> { NSinputStream *_inputStream; NSOutputStream *_outputStream; uint8_t *_buffer;}@property (copy) Nsstring* sourcefilePath;@property (copy) Nsstring* targetfilePath;@property (copy) Nsstring* username;@property (copy) Nsstring* password;@end@implementation NSSendfileOperation- (voID) main{ static int kBufferSize = 4096; _inputStream = [NSinputStream inputStreamWithfileAtPath:self.sourcefilePath]; _outputStream = [NSOutputStream outputStreamToMemory]; _outputStream.delegate = self; [_inputStream open]; [_outputStream open]; _buffer = calloc(1,kBufferSize); while (_inputStream.hasBytesAvailable) { NSInteger bytesRead = [_inputStream read:_buffer maxLength:kBufferSize]; if (bytesRead > 0) { [_outputStream write:_buffer maxLength:bytesRead]; NSLog(@"Wrote %ld bytes to output stream",bytesRead); } } NSData *outputData = [_outputStream propertyForKey:NsstreamDataWrittenToMemoryStreamKey]; NSLog(@"Wrote a total of %lu bytes to output stream.",outputData.length); free(_buffer); _buffer = NulL; [_outputStream close]; [_inputStream close];}- (voID) stream:(Nsstream *)aStream handleEvent:(NsstreamEvent)eventCode{ // Handle output stream errors such as disconnections here}@endint main (int argc,const char * argv[]){ @autoreleasepool { NSOperationQueue *sendQueue = [[NSOperationQueue alloc] init]; NSSendfileOperation *sendOp = [[NSSendfileOperation alloc] init]; sendOp.username = @"test"; sendOp.password = @"test"; sendOp.sourcefilePath = @"/Users/eric/bin/data/english-words.txt"; sendOp.targetfilePath = @"/Users/eric/Desktop/english-words.txt"; [sendQueue addOperation:sendOp]; [sendQueue waitUntilAllOperationsAreFinished]; } return 0;}@H_404_45@ 总结
以上是内存溢出为你收集整理的objective-c – NSOutputStream完成后关闭连接全部内容,希望文章能够帮你解决objective-c – NSOutputStream完成后关闭连接所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)