在网上搜索了一些资料下载远程文件夹及其里面的内容,然后结果都只是下载单个文件,并没有提及到下载文件夹中的东西。然后研究了下一个三方的ftp下载文件内容之后,解决了下载远程文件夹中内容的问题。
1.可以将远程文件夹的内容打包成zip的形式,然后通过下载单个文件的形式先下载到沙盒,然后解压沙盒中为zip。下载单个文件可以参照我写的http下载文件。网上也有ftp下载单个文件资料,自己查找。我用的是SSZipArchive这个三方来解压。
2.直接下载,不用压缩。用的三方是GoldRaccoon这个三方
1.)去下载三方并且导入Sources
2.)在Build Phases中添加CFNetwork和Foundation包
3.)目录结构类似这样子的
4.)我直接在Main.storyboard中添加一个button并关联成事件做点击下载用。
5.)我自己搭建的ftp服务器建立站点,下面是我服务器中的目录
目录内容:
5.)代码ViewController中的代码(代码中我已经标注了,就不再说了)
#import "ViewController.h"
#import "GRRequestsManager.h"
#import "GRListingRequest.h"
@interface ViewController ()<GRRequestsManagerDelegate>
@property (nonatomic, strong) GRRequestsManager *requestsManager;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
}
#pragma mark *** Events ***
// 列表
- (IBAction)respondsToListing:(UIButton *)sender {
//列表localuser下的文件夹目录,这里做的只是列表目录下面有什么
[self.requestsManager addRequestForListDirectoryAtPath:@"localuser"];
[self.requestsManager startProcessingRequests];
}
#pragma mark *** GRRequestsManagerDelegate ***
//代理方法,每次执行列表方法都会走这个方法
- (void)requestsManager:(id<GRRequestsManagerProtocol>)requestsManager didCompleteListingRequest:(id<GRRequestProtocol>)request listing:(NSArray *)listing{
//沙盒目录
NSString *documentsDirectoryPath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingString:@"/localuser"];
GRListingRequest *req = (GRListingRequest *)request;
//远程文件夹列表
NSLog(@"%@",listing);
//打印创建的目录
NSLog(@"%@",documentsDirectoryPath);
NSFileManager *fileManager = [NSFileManager defaultManager];
//文件夹列表枚举
[listing enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
if ([[obj pathExtension] isEqualToString:@""]) {
//整个地址,在沙盒中创建和远程文件一样的文件夹目录
NSString *zhenggedizhi = [documentsDirectoryPath stringByAppendingString:[NSString stringWithFormat:@"%@/%@",req.path,obj]];
//如果沙盒中的这个文件夹不存在就创建
if (![fileManager fileExistsAtPath:zhenggedizhi]) {
[fileManager createDirectoryAtPath:zhenggedizhi withIntermediateDirectories:YES attributes:nil error:nil];
}
//然后接着递归列举文件夹下的子文件夹下的目录
[self.requestsManager addRequestForListDirectoryAtPath:[NSString stringWithFormat:@"%@%@",req.path,obj]];
[self.requestsManager startProcessingRequests];
}else{
//如果目录下的不是文件夹,则下载这个文件到沙盒的指定目录下
[self.requestsManager addRequestForDownloadFileAtRemotePath:[NSString stringWithFormat:@"%@/%@",req.path,obj] toLocalPath:[documentsDirectoryPath stringByAppendingPathComponent:[NSString stringWithFormat:@"%@%@",req.path,obj]]];
[self.requestsManager startProcessingRequests];
}
}];
}
#pragma mark *** Lazy loading ***
- (GRRequestsManager *)requestsManager{
if (!_requestsManager) {
//初始化请求类,需要ftp的地址,用户名密码
//这里是我自己在服务器上搭建了一个ftp服务器,并建立站点
_requestsManager = [[GRRequestsManager alloc]initWithHostname:@"ftp://10.185.36.12:81" user:@"zhaoqian" password:@"Zq123"];
// 设置代理
_requestsManager.delegate = self;
}
return _requestsManager;
}
@end
6.)效果
首先是列表和沙盒地址
comond+shift+g打开沙盒地址看到
也就是我下载成功了。
注意:暂时不支持中文文件名的文件下载和文件创建。有什么问题可以联系我探讨。希望对大家有帮助!
这两天解决了中文乱码的问题,ftp服务器的编码格式是gbk格式的所以要在一些地方修改
首先是包里面的内容在GRListingRequest.m中找到 case NSStreamEventEndEncountered里面的内容改为:
NSUInteger offset = 0;
CFIndex parsedBytes;
uint8_t *bytes = (uint8_t *)[self.receivedData bytes];
NSUInteger totalbytes = [self.receivedData length];
do {
CFDictionaryRef listingEntity = NULL;
parsedBytes = CFFTPCreateParsedResourceListing(NULL, &bytes[offset], totalbytes - offset, &listingEntity);
if (parsedBytes > 0) {
if (listingEntity != NULL) {
NSDictionary *entryToAdd = [self _entryByReencodingNameInEntry: (__bridge NSDictionary *)listingEntity encoding: CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingGB_18030_2000)];
self.filesInfo = [self.filesInfo arrayByAddingObject:entryToAdd];
}
offset += parsedBytes;
}
} while (parsedBytes > 0);
[self.streamInfo streamComplete:self];
break;
再在下面添加一个方法:
- (NSDictionary*)_entryByReencodingNameInEntry:(NSDictionary *)entry encoding:(NSStringEncoding)newEncoding {
// CFFTPCreateParsedResourceListing always interprets the file name as MacRoman,
// which is clearly bogus <rdar://problem/7420589>. This code attempts to fix
// that by converting the Unicode name back to MacRoman (to get the original bytes;
// this works because there's a lossless round trip between MacRoman and Unicode)
// and then reconverting those bytes to Unicode using the encoding provided.
NSDictionary * result;
NSString * name;
NSData * nameData;
NSString * newName;
newName = nil;
// Try to get the name, convert it back to MacRoman, and then reconvert it
// with the preferred encoding.
name = [entry objectForKey:(id) kCFFTPResourceName];
if (name != nil) {
assert([name isKindOfClass:[NSString class]]);
nameData = [name dataUsingEncoding:NSMacOSRomanStringEncoding];
if (nameData != nil) {
newName = [[NSString alloc] initWithData:nameData encoding:newEncoding];
}
}
// If the above failed, just return the entry unmodified. If it succeeded,
// make a copy of the entry and replace the name with the new name that we
// calculated.
if (newName == nil) {
// assert(NO); // in the debug builds, if this fails, we should investigate why
result = (NSDictionary *) entry;
}
else {
NSMutableDictionary * newEntry;
newEntry = [entry mutableCopy];
assert(newEntry != nil);
[newEntry setObject:newName forKey:(id) kCFFTPResourceName];
result = newEntry;
}
return result;
}
其次在GRRequest.m中找到
- (NSString *)encodeString:(NSString *)string;
{
NSString *urlEncoded = (__bridge_transfer NSString *)CFURLCreateStringByAddingPercentEscapes(
NULL,
(__bridge CFStringRef) string,
NULL,
(CFStringRef)@"!*'\"();:@&=+$,?%#[]%",
CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingGB_18030_2000));
return urlEncoded;
}
将其改成gbk编码的格式
最后在ViewController.m中做出如下修改
添加一个解URLGBK编码的方法
- (NSString *)decodeFromPercentEscapeString: (NSString *) input
{
NSMutableString *outputStr = (__bridge NSString *)CFURLCreateStringByReplacingPercentEscapesUsingEncoding(kCFAllocatorDefault,
(CFStringRef)input,
CFSTR(""),
kCFStringEncodingGB_18030_2000);
return outputStr;
}
然后将以前文件中的req.path 改为上面这个方法解码后的字符串
ViewController.m整个代码如下
#import "ViewController.h"
#import "GRRequestsManager.h"
#import "GRListingRequest.h"
@interface ViewController ()<GRRequestsManagerDelegate>
@property (nonatomic, strong) GRRequestsManager *requestsManager;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
}
#pragma mark *** Events ***
// 列表
- (IBAction)respondsToListing:(UIButton *)sender {
//列表localuser下的文件夹目录,这里做的只是列表目录下面有什么
[self.requestsManager addRequestForListDirectoryAtPath:@"dirt"];
[self.requestsManager startProcessingRequests];
}
#pragma mark *** GRRequestsManagerDelegate ***
//代理方法,每次执行列表方法都会走这个方法
- (void)requestsManager:(id<GRRequestsManagerProtocol>)requestsManager didCompleteListingRequest:(id<GRRequestProtocol>)request listing:(NSArray *)listing{
//沙盒目录
NSString *documentsDirectoryPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
NSLog(@"%@",documentsDirectoryPath);
GRListingRequest *req = (GRListingRequest *)request;
//远程文件夹列表
NSLog(@"%@",listing);
//打印创建的目录
NSFileManager *fileManager = [NSFileManager defaultManager];
//文件夹列表枚举
[listing enumerateObjectsUsingBlock:^(NSString * obj, NSUInteger idx, BOOL * _Nonnull stop) {
if ([[obj pathExtension] isEqualToString:@""]) {
//整个地址,在沙盒中创建和远程文件一样的文件夹目录
NSString *zhenggedizhi = [documentsDirectoryPath stringByAppendingString:[NSString stringWithFormat:@"%@%@",[self decodeFromPercentEscapeString:req.path],obj]];
//如果沙盒中的这个文件夹不存在就创建
if (![fileManager fileExistsAtPath:zhenggedizhi]) {
[fileManager createDirectoryAtPath:zhenggedizhi withIntermediateDirectories:YES attributes:nil error:nil];
}
//然后接着递归列举文件夹下的子文件夹下的目录
[self.requestsManager addRequestForListDirectoryAtPath:[NSString stringWithFormat:@"%@%@",[self decodeFromPercentEscapeString:req.path],obj]];
[self.requestsManager startProcessingRequests];
}else{
if ([obj isEqualToString:@"end.txt"]) {
NSLog(@"finished.........");
}
//如果目录下的不是文件夹,则下载这个文件到沙盒的指定目录下
if (![fileManager fileExistsAtPath:[documentsDirectoryPath stringByAppendingPathComponent:[NSString stringWithFormat:@"%@%@",[self decodeFromPercentEscapeString:req.path],obj]]]) {
[self.requestsManager addRequestForDownloadFileAtRemotePath:[NSString stringWithFormat:@"%@%@",[self decodeFromPercentEscapeString:req.path],obj] toLocalPath:[documentsDirectoryPath stringByAppendingPathComponent:[NSString stringWithFormat:@"%@%@",[self decodeFromPercentEscapeString:req.path],obj]]];
NSLog(@"%@",[NSString stringWithFormat:@"%@%@",[self decodeFromPercentEscapeString:req.path],obj]);
[self.requestsManager startProcessingRequests];
}
}
}];
}
- (NSString *)decodeFromPercentEscapeString: (NSString *) input
{
NSMutableString *outputStr = (__bridge NSString *)CFURLCreateStringByReplacingPercentEscapesUsingEncoding(kCFAllocatorDefault,
(CFStringRef)input,
CFSTR(""),
kCFStringEncodingGB_18030_2000);
return outputStr;
}
#pragma mark *** Lazy loading ***
- (GRRequestsManager *)requestsManager{
if (!_requestsManager) {
//初始化请求类,需要ftp的地址,用户名密码
//这里是我自己在服务器上搭建了一个ftp服务器,并建立站点
_requestsManager = [[GRRequestsManager alloc]initWithHostname:@"ftp://10.185.36.12:81" user:@"zhaoqian" password:@"Zq123"];
// 设置代理
_requestsManager.delegate = self;
}
return _requestsManager;
}
@end
如果URL路劲不对会出现一个 kCFErrorDomainCFNetwork error 200的错误