iOSでテンポラリフォルダに日本語のファイル名を保存できない。

解決


のぶ  2023-02-08 07:35:13  No: 150776  IP: [192.*.*.*]

DelphiのFMXの開発を行っております。

インターネット上のファイルをTNetHTTPRequest.GetメソッドでMemoryStreamに取得し、
ローカルストレージのテンポラリフォルダにファイル名を日本語にして保存していますが、
保存したファイルをブラウザで開こうとすると「指定されたファイルが見つかりません」
というエラーダイアログが表示されます。TNetHTTPRequest.Getでエラーは起きていません。
ファイル名を英数字にした場合は、問題なくブラウザで表示できます。

どなたか原因が分かる方おられませんでしょうか?

【バージョン】
RAD Studio 11 Alexandria
Embarcadero® Delphi 11.0 バージョン 28.0.42600.6491

【ソース】

unit Unit1;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs,
  FMX.Controls.Presentation, FMX.StdCtrls,
  System.Net.HttpClientComponent,System.IOUtils, System.Net.URLClient,
  System.Net.HttpClient,
  FMX.WebBrowser
  ;

type
  TForm1 = class(TForm)
    Button1: TButton;
    NetHTTPClient1: TNetHTTPClient;
    NetHTTPRequest1: TNetHTTPRequest;
    WebBrowser1: TWebBrowser;
    procedure Button1Click(Sender: TObject);
  private
    { private 宣言 }
  public
    { public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.fmx}

procedure TForm1.Button1Click(Sender: TObject);
var
  LFileName: string;
  LResponseContent: TMemoryStream;
  App: Pointer;
begin
  LResponseContent := TMemoryStream.Create;
  try

    NetHTTPRequest1.Get('https://www5.cao.go.jp/keizai-shimon/kaigi/minutes/2023/0124/gijiyoushi.pdf', LResponseContent);

    LFileName := TPath.Combine(TPath.GetTempPath, '資料.pdf');
    LResponseContent.SaveToFile(LFileName);

    WebBrowser1.URL := 'file://' + LFileName;

  finally
    LResponseContent.Free;
  end;
end;

end.

編集 削除
take  2023-02-08 07:52:34  No: 150777  IP: [192.*.*.*]

URLに漢字を使う場合はURLエンコード・デコードが必要じゃないかな?

例えば「あ」は 「%E3%81%82」という9バイトの文字列になります

urlエンコードはDelphiに見つからなかったから作ったけど
urlの文字1つずつ見て漢字だったら

    c = 'あ';
    for j := 1 to Length(c) do begin                              // 長さ分ループ
      a := c[j];                                                  // 1文字取り出す
      d := Ord(a);                                                // 文字コードに変換
      s := s + '%' +IntToHex(d,2);                                // %E5%83...形式に変換
    end;

こんな感じでエンコードしてます。

アドレスバーに漢字を入力したときの挙動はブラウザごとに異なるかも

編集 削除
のぶ  2023-02-09 06:19:44  No: 150784  IP: [192.*.*.*]

takeさん
いつもありがとうございます。
日本語のファイル名ですがURLエンコードで保存できました。
ちにみにURLエンコードは TNetEncoding.URL.Encode関数 があります。
アドバイス大変ありがとうございました。

ただ、前回投稿させていただいた共有メニューでSLACK等でファイル渡しを行うと
%E8%B3%87%E6%96%99.pdf というファイル名になってしまいました。
ファイル保存するときに%をエスケープしないといけないのかもしれません。

そこでTNetHTTPRequestのGetでファイルを、MemoryStreamではなく、
FileStreamに取得したら、日本語のファイル名で保存でき、かつ、共有メニューから
ファイル渡しした際も正しい日本語表示にすることができました。

参考までサンプルソースを貼っておきます。



■サンプルソース


unit Unit1;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs,
  FMX.Controls.Presentation, FMX.StdCtrls,
  System.Net.HttpClientComponent,System.IOUtils, System.Net.URLClient,
  System.Net.HttpClient,
  FMX.WebBrowser
{$IFDEF IOS}
  ,DW.ShareItems
{$ENDIF}
  ;

type
  TForm1 = class(TForm)
    Button1: TButton;
    NetHTTPClient1: TNetHTTPClient;
    NetHTTPRequest1: TNetHTTPRequest;
    WebBrowser1: TWebBrowser;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    { private 宣言 }
{$IFDEF IOS}
    FExcluded: TShareActivities;
    FShareItems: TShareItems;
{$ENDIF}
  public
    { public 宣言 }
  end;

var
  Form1: TForm1;

implementation
uses
  System.Permissions,
  DW.Consts.Android, DW.Permissions.Helpers,
  System.NetEncoding;

{$R *.fmx}

procedure TForm1.Button1Click(Sender: TObject);
var
  LFileName: string;
  LResponseContent: TFileStream;
  App: Pointer;
begin
  LFileName := TPath.Combine(TPath.GetTempPath, '資料.pdf');
  LResponseContent := TFileStream.Create(LFileName, fmCreate);
  try

    NetHTTPRequest1.Get('https://www5.cao.go.jp/keizai-shimon/kaigi/minutes/2023/0124/gijiyoushi.pdf', LResponseContent);

    LFileName := TPath.Combine(TPath.GetTempPath, TNetEncoding.URL.Encode('資料.pdf'));
    WebBrowser1.URL := 'file://' + LFileName;

  finally
    LResponseContent.Free;
  end;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
{$IFDEF IOS}
  PermissionsService.RequestPermissions([cPermissionReadExternalStorage, cPermissionWriteExternalStorage],
    procedure(const APermissions: TPermissionArray; const AGrantResults: TPermissionStatusArray)
    var
      LFileName: string;
    begin
      if AGrantResults.AreAllGranted then begin
        LFileName := TPath.Combine(TPath.GetTempPath, '資料.pdf');
        FShareItems.AddFile(LFileName);
        FShareItems.Share(Button2, FExcluded);
      end;
    end
  );
{$ENDIF}
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
{$IFDEF IOS}
  FShareItems := TShareItems.Create;
{$ENDIF}
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
{$IFDEF IOS}
  FShareItems.Free;
{$ENDIF}
end;

end.

編集 削除
のぶ  2023-02-09 06:20:04  No: 150785  IP: [192.*.*.*]

解決入れるのを忘れていました。

編集 削除