这两天研究了一下iOS中的 FTP文件传送。主要参考了 官方的demo 地址是:https://developer.apple.com/library/ios/samplecode/SimpleFTPSample/Introduction/Intro.html
需要引入 CFNetwork.framework
#include <sys/socket.h>
#include <sys/dirent.h>
#include <CFNetwork/CFNetwork.h>
用到NSStream的子类,NSInputStream(读流) 和NSOutputStream(写流) 用来接收和发送数据。
以demo中的 从服务器中get到一个 图片为例
首先创建一个inputstream,用来读服务器中图片的数据。
self.networkStream = CFBridgingRelease(
CFReadStreamCreateWithFTPURL(NULL, (__bridge CFURLRef) url)//url为ftp://....
);
[self.networkStream setProperty:@"hlct" forKey:(id)kCFStreamPropertyFTPUserName];//服务器的userName
[self.networkStream setProperty:@"hlct2014" forKey:(id)kCFStreamPropertyFTPPassword];//密码
self.networkStream.delegate = self;
[self.networkStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[self.networkStream open];
然后创建一个outstream, 把用inputstream读到的数据,写到沙盒中。
self.fileStream = [NSOutputStream outputStreamToFileAtPath:self.filePath append:NO];
[self.fileStream open];
接收到的 数据写在delegate中。
- (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: { //接收到内容的时候
NSInteger bytesRead;
uint8_t buffer[32768];
[self updateStatus:@"Receiving"];
// Pull some data off the network.
bytesRead = [self.networkStream read:buffer maxLength:sizeof(buffer)];
if (bytesRead == -1) {etwork read error"];
} else if (bytesRead == 0) {//完成
[self stopReceiveWithStatus:nil了];
} else {
NSInteger bytesWritten;
NSInteger bytesWrittenSoFar;
// Write to the file.
bytesWrittenSoFar = 0;
do {
bytesWritten = [self.fileStream write:&buffer[bytesWrittenSoFar] maxLength:(NSUInteger) (bytesRead - bytesWrittenSoFar)];
assert(bytesWritten != 0);
if (bytesWritten == -1) {
[self stopReceiveWithStatus:@"File write error"];
break;
} else {
bytesWrittenSoFar += bytesWritten;
}
} while (bytesWrittenSoFar != bytesRead);
}
} break;
case NSStreamEventHasSpaceAvailable: { //向服务器中写文件时,写到此处
assert(NO); // should never happen for the output stream
} break;
case NSStreamEventErrorOccurred: { //链接出错
[self stopReceiveWithStatus:@"Stream open error"];
} break;
case NSStreamEventEndEncountered: {
// ignore
} break;
default: {
assert(NO);
} break;
}
如果是查看文件列表的时候, 用NSMutableData来接收数据。然后对数据进行下面的解析
- (void)parseListData
{
NSMutableArray * newEntries;
NSUInteger offset;
newEntries = [NSMutableArray array];
assert(newEntries != nil);
offset = 0;
do {
CFIndex bytesConsumed;
CFDictionaryRef thisEntry;
thisEntry = NULL;
assert(offset <= [self.listData length]);
//解析讲data转换成 CFDictionaryRef
bytesConsumed = CFFTPCreateParsedResourceListing(NULL, &((const uint8_t *) self.listData.bytes)[offset], (CFIndex) ([self.listData length] - offset), &thisEntry);
if (bytesConsumed > 0) {
// It is possible for CFFTPCreateParsedResourceListing to return a
// positive number but not create a parse dictionary. For example,
// if the end of the listing text contains stuff that can't be parsed,
// CFFTPCreateParsedResourceListing returns a positive number (to tell
// the caller that it has consumed the data), but doesn't create a parse
// dictionary (because it couldn't make sense of the data). So, it's
// important that we check for NULL.
if (thisEntry != NULL) {
NSDictionary * entryToAdd;
entryToAdd = [self entryByReencodingNameInEntry:(__bridge NSDictionary *) thisEntry encoding:NSUTF8StringEncoding];
[newEntries addObject:entryToAdd];
}
// We consume the bytes regardless of whether we get an entry.
offset += (NSUInteger) bytesConsumed;
}
if (thisEntry != NULL) {
CFRelease(thisEntry);
}
if (bytesConsumed == 0) {//该条记录并为传完 跳出循环
// We haven't yet got enough data to parse an entry. Wait for more data
// to arrive.
break;
} else if (bytesConsumed < 0) {//出错
// We totally failed to parse the listing. Fail.
[self stopReceiveWithStatus:@"Listing parse failed"];
break;
}
} while (YES);
if ([newEntries count] != 0) {
[self addListEntries:newEntries]; //将dic添加到本类中dic的属性中
}
if (offset != 0) {
[self.listData replaceBytesInRange:NSMakeRange(0, offset) withBytes:NULL length:0];//将解析完成的data移除。
}
}
好了 差不多就这些东西了 想研究的,可以从官网下载下来这个demo,自己查看。