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.
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;
こんな感じでエンコードしてます。
アドレスバーに漢字を入力したときの挙動はブラウザごとに異なるかも
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.
解決入れるのを忘れていました。
ツイート | ![]() |