问题
My case is quite strange: I practically used the example "SimpleFTPSample" (some small variation of the type [self.networkStream setProperty: (id) kCFBooleanFalse forKey: (NSString *) kCFStreamPropertyFTPAttemptPersistentConnection]; to avoid keeping the connection alive WiFi/3G) to perform transfer operations FTP file but despite not having errors of any kind, your downloaded file is corrupted if you use an ftp site: To resolve this issue, simply add a sleep (3)! This function (sleep) must be performed BEFORE [self.networkStream close]; Warning: If I change the ftp site I have no problem without the "sleep (3)"!
I did not understand anything ... Thanks for any type of aid
I attach my sample code.
- (void)_startSend
{
BOOL success;
NSURL * url;
CFWriteStreamRef ftpStream;
assert(self.networkStream == nil); // don't tap receive twice in a row!
assert(self.fileStream == nil); // ditto
assert(self.filePath == nil); // self.filePath rappresenta il percorso del file da inviare
self.attendere.hidden = FALSE;
// First get and check the URL.
defaults = [NSUserDefaults standardUserDefaults];
NSString * Cartella_ZIP = [[defaults objectForKey:kIndirizzoIpUploadKey]
stringByAppendingString:self.Nome_File_da_Inviare];
url = [[iSalesAgentAppDelegate sharedAppDelegate] smartURLForString:Cartella_ZIP];
success = (url != nil);
// If the URL is bogus, let the user know. Otherwise kick off the connection.
if ( ! success) {
self.statuslabel.text = @"Indirizzo FTP non valido!";
} else {
NSLog(@"nome file %@",self.Nome_File_da_Inviare);
self.filePath = [self.Cartella_Lavoro stringByAppendingPathComponent:self.Nome_File_da_Inviare];
assert(self.filePath != nil);
self.fileStream = [NSInputStream inputStreamWithFileAtPath:self.filePath];
assert(self.fileStream != nil);
[self.fileStream open];
// Open a CFFTPStream for the URL.
ftpStream = CFWriteStreamCreateWithFTPURL(NULL, (__bridge CFURLRef) url);
assert(ftpStream != NULL);
self.networkStream = (__bridge NSOutputStream *) ftpStream;
success = [self.networkStream setProperty:[defaults objectForKey:kUsernameFtpKey] forKey:(id)kCFStreamPropertyFTPUserName];
assert(success);
success = [self.networkStream setProperty:[defaults objectForKey:kPasswordFtpKey] forKey:(id)kCFStreamPropertyFTPPassword];
assert(success);
[self.networkStream setProperty:(id)kCFBooleanFalse forKey:(NSString *)kCFStreamPropertyFTPAttemptPersistentConnection];
self.networkStream.delegate = self;
[self.networkStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[self.networkStream open];
CFRelease(ftpStream);
[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
{
assert(aStream == self.networkStream);
NSString * stringa_byte_letti =nil;
NSString * stringa_filesize =nil;
NSNumber * number = nil;
self.filesize = [[[NSFileManager defaultManager] attributesOfItemAtPath:self.filePath error:nil] fileSize];
NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];
[numberFormatter setNumberStyle:kCFNumberFormatterDecimalStyle];
[numberFormatter setGroupingSeparator:@"."];
switch (eventCode) {
case NSStreamEventOpenCompleted: {
// Added: Finally get filesize
[self _updateStatus:@"Aperta Connessione"];
filesize = 0; byte_scritti = 0;
} break;
case NSStreamEventHasBytesAvailable: {
[self _stopSendWithStatus:@"Network write error"];
assert(NO); // should never happen for the output stream
} break;
case NSStreamEventHasSpaceAvailable: {
[self _updateStatus:@"Invio Ordine..."];
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) {
sleep(3);
[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);
byte_scritti += bytesWritten;
if (bytesWritten == -1) {
[self _stopSendWithStatus:@"Network write error"];
} else {
self.bufferOffset += bytesWritten;
}
}
number = [NSNumber numberWithDouble:byte_scritti];
stringa_byte_letti = [numberFormatter stringForObjectValue:number];
number = [NSNumber numberWithInteger:self.filesize];
stringa_filesize = [numberFormatter stringForObjectValue:number];
[self _updateStatus:[NSString stringWithFormat:@"Invio File nr. %i di %i: Totale byte %@ - byte scritti : %@", [self.numero_file_da_inviare intValue]+1 ,[Array_FileZip count],stringa_filesize,stringa_byte_letti ]];
// Pull some data off the network.
NSNumber * percentuale_progress = [NSNumber numberWithFloat: (float)byte_scritti / (float)self.filesize];
[self performSelectorOnMainThread:@selector(Aggiorna_ProgressBar:) withObject:percentuale_progress waitUntilDone:YES];
} break;
case NSStreamEventErrorOccurred: {
[self _stopSendWithStatus:@"File Dati non trovato!"];
} break;
case NSStreamEventEndEncountered: {
// evento ignorato
} break;
default: {
[self _stopSendWithStatus:@"Network write error"];
assert(NO);
} break;
}
}
回答1:
same problem here. As far as I understand the problem is that when you work with no persistent connection, when you call "close" the connection with the FTP server is immediately closed (before the last chunk of data is effectively transmitted). The problem is that the close doesn't perform a "flush" of data. I'm stucked with this problem too.
来源:https://stackoverflow.com/questions/12845158/nsstream-dont-send-all-data