sci

最果て風呂

Objective-C でパスに日本語を含むファイルを開く

普段は JavaScript 版ばかりを使っているので気付かなかったのだが、メニューバーからオープンダイアログを使ってファイルを読み込ませる場合、パスやファイル名に日本語の文字列があると開くことができなかった。また、ファイルの文字コードUTF-8 以外のものも開くことができなかった。う〜めんどい。

とりあえず下記のようにすればパスに日本語が含まれていてもファイルを開けるようになった。ファイルの文字コードUTF-8 限定のまま。

// ファイルから文章を読み込む
- (IBAction)readFromFile:(id)sender {
  NSOpenPanel *oPanel = [NSOpenPanel openPanel];

  [oPanel beginWithCompletionHandler:^(NSInteger result) {
  if (result == NSFileHandlingPanelOKButton) {
    // パスを取得
    NSError *err = nil;
    NSURL *ifPath = [[oPanel URLs] objectAtIndex:0];
    // UTF-8 かな?
    NSString *text = [NSString stringWithContentsOfFile:
                      [[[ifPath absoluteString] substringFromIndex:7]
              stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]
                                                  encoding:NSUTF8StringEncoding
                                                     error:&err];
    if (err) {
      _inputTextArea.string = @"UTF-8 形式のファイルしか読み込めないぞ!\n";
    } else {
      _inputTextArea.string = text;
      //NSLog(@"選択したファイルは '%@' ですか?", ifPath);
    }

  } else if (result == NSFileHandlingPanelCancelButton) {
    //NSLog(@"キャンセルボタンを押しました");
  } else {
    //NSLog(@"エラーかも");
  }
  }];
}

ちょっとネストしていてわかりにくいけれど、

[[[fPath absoluteString] substringFromIndex:7]
              stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]

の部分が NSURL から NSString に文字列を変更している部分。NSURL のままだとパーセントエスケープされた文字列なのだ。例えば テスト.txt だと %E3%83%86%E3%82%B9%E3%83%88.txt のようになってしまっている。

検索で引掛った Apple の「ファイルシステムプログラミングガイド」に倣って beginWithCompletionHandler:^(NSInteger result) を使うようにした。Objective-C もかなり改定してるのね。

stringWithContentsOfFile: のオプション encoding:NSUTF8StringEncoding を例えば NSShiftJISStringEncoding にすると、Shift-JIS のファイルを開ける。場合分けが面倒なので UTF-8 以外のファイルはダメよんってことにした。

ファイルを保存する場合も、日本語のファイル名にするとパーセントエスケープ文字列になってしまうので変更していく。文字コードUTF-8 で保存できているので、こちらはパスの問題だけ対処すれば良さそう。

読み込みの時と同じようにして日本語ファイル名で保存できるようになった。

// 結果エリアのテキストをファイルに保存する
- (IBAction)writeToFile:(id)sender {
  NSSavePanel *sPanel = [NSSavePanel savePanel];

  [sPanel beginWithCompletionHandler:^(NSInteger result) {
  if(result == NSFileHandlingPanelOKButton) {
    // パスを取得
    NSURL *ofPath = [sPanel URL];
    [_resultTextArea.string writeToFile:
     [[[ofPath absoluteString] substringFromIndex:7]
      stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]
                             atomically:YES
                               encoding:4
                                  error:NULL];

    //NSLog(@"保存したファイルは '%@' ですか?", ofPath);

  }
  else if (result == NSFileHandlingPanelCancelButton) {
      //NSLog(@"キャンセルボタンを押しました");
  }
  else {
    //NSLog(@"エラーかも");
  }
  }];
}

しかしほんとメソッド名が長いわ。