iOS ftp下载远程文件夹内容(文件夹目录结构不变)

来源:互联网 发布:ubuntu安装软件 编辑:程序博客网 时间:2024/06/11 00:35

在网上搜索了一些资料下载远程文件夹及其里面的内容,然后结果都只是下载单个文件,并没有提及到下载文件夹中的东西。然后研究了下一个三方的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的错误

原创粉丝点击