Objective-CのFTPファイル送受信で日本語名ファイルを扱う
iOS端末からFTPサーバーにアクセスし、日本語名のファイルを扱う方法をまとめました。
(今回はWindows上のFTPサーバーのファイルにアクセスするケースを想定しています)
準備(FTPライブラリを組み込みます)
FTP送受信のライブラリはGoldRaccoonを使います。
cocoaPodsを使ってインストールするので、まずcocoaPodsをインストールします。
sudo gem install cocoapods
注:rbenvを使っていてエラーになる場合は、systemのrubyを使いましょう。
プロジェクト(例:JapaneaseFTPSample)直下にPodFileを配置します。
pod "GoldRaccoon"
GoldRaccoonをインストールします。
pod install
JapaneaseFTPSample.xcworkspace
ができているので、これを起動します。
注意点
pod install
でインストールしたものが1.0.1の場合、
iPhone Retina(4-inch 64bit)以外で動かすと例外が発生しました。
GitHub上にある最新ソースでは発生しなくなっているのでSources以下を丸ごと置き換えておきましょう。
補足:アップロード時の不具合が修正された1.0.2で最新ソースと一致しています。
FTP機能の利用
List、Get、Putの機能を使ってみます。
組み込み方法はGoldRaccoonの手順と、GRDemoViewControllerの実装を参考にしました。
1.初期化
initWithHostname: user: password:
2.リクエストの登録
addRequestForListDirectoryAtPath:
addRequestForDownloadFileAtRemotePath: toLocalPath:
addRequestForUploadFileAtLocalPath: toRemotePath:
3.リクエストの実行
startProcessingRequests
4.結果受信(デリゲート)
requestsManager: didScheduleRequest:
requestsManager: didCompleteDownloadRequest:
requestsManager: didCompleteListingRequest: listing:
requestsManager: didCompleteUploadRequest:
requestsManager: didFailWritingFileAtPath: forRequest: error:
requestsManager: didFailRequest: withError:
日本語ファイル対応のポイント
ファイルリスト取得時
ファイルリストを取得にはCFFTPCreateParsedResourceListing
を使用しています。
この関数で取得されたファイル名はMacRomanに変換して格納されているため、元に戻す必要があります。
このことは、Apple公式サンプルのSimpleFTPSampleのListController.mのentryByReencodingNameInEntry:
のところで説明されています。
その後本来のエンコードで取り出します。
- (void)requestsManager:(id<GRRequestsManagerProtocol>)requestsManager didCompleteListingRequest:(id<GRRequestProtocol>)request listing:(NSArray *)listing
{
NSLog(@"requestsManager:didCompleteListingRequest:listing: \n%@", listing);
self.fileLists = nil;
self.fileLists = [[NSMutableArray alloc] init];
// 日本語ファイル名の変換
NSString *name;
NSData *nameData;
NSString *newName;
for (int i = 0; i<[listing count]; i++) {
name = listing[i];
nameData = [name dataUsingEncoding:NSMacOSRomanStringEncoding];
if (nameData != nil) {
newName = [[NSString alloc] initWithData:nameData encoding:NSShiftJISStringEncoding];
[self.fileLists addObject:newName];
}
}
self.getButton.enabled = YES;
[self.fileListView reloadData];
}
ファイルダウンロード時
ファイル名が日本語なのでURLエンコードする必要があります。
pod installでインストールした1.0.1では自前で対応する必要がありましたが、
GitHubから取得したソースでは内部でエンコードされるようになっていました。
しかしUFT8固定のため、クラス拡張を使ってエンコードすることにしました。
# import "GRRequest.h"
@interface GRRequest(Encode)
@end
# import "GRRequest+encode.h"
# import <objc/runtime.h>
@implementation GRRequest(Encode)
- (NSString *)encodeString:(NSString *)string;
{
NSString *urlEncoded = (__bridge_transfer NSString *)CFURLCreateStringByAddingPercentEscapes(
NULL,
(__bridge CFStringRef) string,
NULL,
(CFStringRef)@"!*'\"();:@&=+$,?%#[]% ",
kCFStringEncodingMacRoman);
return urlEncoded;
}
@end
リスト取得時を参考にMacRomanに変換します。
- (IBAction)getFile:(id)sender {
[self _setupManager];
if (self.ftpFileName == nil) {
return;
}
NSData *nameData = [self.ftpFileName dataUsingEncoding:NSShiftJISStringEncoding];
if (nameData == nil) {
return;
}
NSString *fileName = [[NSString alloc] initWithData:nameData encoding:NSMacOSRomanStringEncoding];
[self.requestsManager addRequestForDownloadFileAtRemotePath:fileName toLocalPath:[NSTemporaryDirectory() stringByAppendingPathComponent:self.ftpFileName]];
[self.requestsManager startProcessingRequests];
}
ファイルアップロード時
ダウンロード時と同じように変換します。
- (IBAction)putFile:(id)sender {
[self _setupManager];
NSData *nameData = [self.ftpFileName dataUsingEncoding:NSShiftJISStringEncoding];
if (nameData == nil) {
return;
}
NSString *fileName = [[NSString alloc] initWithData:nameData encoding:NSMacOSRomanStringEncoding];
[self.requestsManager addRequestForUploadFileAtLocalPath:[NSTemporaryDirectory() stringByAppendingPathComponent:self.ftpFileName] toRemotePath:fileName];
[self.requestsManager startProcessingRequests];
}
今回作成したサンプルコードはGitHubにあげておきます。
JapaneaseFTPSample