67
83

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

[JavaScript] ファイル選択ダイアログを表示してファイルを読み書きする

Last updated at Posted at 2018-01-18

※2024-09-10: 記事を全体的に編集しました。

本記事では、ユーザーが <a> 要素や <input> 要素をクリックしたタイミングでなく、JavaScript のコード中の好きなタイミングでファイル選択ダイアログを出す方法について説明します。

click イベントが発生してから何か処理をした後にダイアログを出したい場合も有効です。

※新しいタブでファイルを表示する場合またはファイルを開く場合、ユーザーの操作によってコードが実行されなければ多くの WEB ブラウザでブロックされます。

本記事では document.createElement() で HTML 要素を作成しますが、静的な HTML でも同様です。

1. ファイルを保存する

データから URL を生成する方法がいくつか有ります:

  • オブジェクト URL を使う
  • データ URL を使う

生成した URL を <a> 要素で指定し click イベントを発火することで、ファイルを保存することが出来ます。

※ WEB ブラウザの設定によってはファイル選択ダイアログを表示せずにファイルを保存する場合があります。

参考「HTMLElement: click() メソッド - Web API | MDN

Firefox バージョン 74 以前は click イベントを発生させるために <a> 要素を DOM 上に追加する必要がありましたが、最新版では不要です。

参考「DOM - Firefox 75 for developers - Mozilla | MDN

1.1. オブジェクト URL を使う場合

URL.createObjectURL() を用いて以下のオブジェクトからオブジェクト URL を生成出来ます:

  • File
  • Blob
  • MediaSource

※オブジェクト URL が不要になったら URL.revokeObjectURL() で解放してください。

const blob = new Blob(['foo\n'], { type: 'text/plain' });

const a = document.createElement('a');
a.href = URL.createObjectURL(blob);
a.download = 'foo.txt';

a.click();

参考「URL: createObjectURL() 静的メソッド - Web API | MDN

1.2. データ URL を使う場合

データ URL を用いてもファイルの保存が可能ですが、データ URL を使用することによって様々な問題が発生する可能性があるため注意が必要です。

プレーンテキストや JSON などのサイズがあまり大きくないファイルを保存する場合に使用します。

※本記事ではプレーンテキストの例を記載しますが、Base64 エンコードを用いてバイナリデータも扱えます。

const text = 'foo\n';

const a = document.createElement('a');
a.href = 'data:text/plain,' + encodeURIComponent(text);
a.download = 'foo.txt';

a.click();

参考「データ URL - URI | MDN
参考「よくある問題 - データ URL - URI | MDN

1.3. その他の方法

location.href = url;open(url, '_blank'); を用いることで、オブジェクト URL をファイルとして扱うことが出来ます。

※データ URL の場合は多くの WEB ブラウザでセキュリティ上の都合でブロックされます。

const blob = new Blob(['foo\n'], { type: 'text/plain' });

location.href = URL.createObjectURL(blob);
const blob = new Blob(['foo\n'], { type: 'text/plain' });

open(URL.createObjectURL(blob), '_blank');

参考「location: href プロパティ - Web API | MDN
参考「Window: open() メソッド - Web API | MDN

2. ファイルを開く

<input type="file"> で click イベントを発火することで、ファイルを開くことが出来ます。

const showOpenFileDialog = () => new Promise(resolve => {
	const input = document.createElement('input');
	input.type = 'file';
	input.accept = 'text/plain';
	input.onchange = () => { resolve(input.files); };
	input.click();
});

(async () => {

	const files = await showOpenFileDialog();
 
	const content = await files[0].text();
	console.log(content);
 
})();

参考「<input type="file"> - HTML: ハイパーテキストマークアップ言語 | MDN
参考「HTML 属性: accept - HTML: ハイパーテキストマークアップ言語 | MDN
参考「HTMLInputElement: files プロパティ - Web API | MDN
参考「HTMLElement: click() メソッド - Web API | MDN

上記ではテキストを読み込むため file.text() を用いていますが、ファイルは様々な扱い方が可能です:

  • URL.createObjectURL(file) の URL を用いる
    • 画像の表示等
  • ファイルを他の型で扱う
    • file.arrayBuffer(): ArrayBuffer
    • file.bytes(): Uint8Array
      • ※多くの環境で未実装
    • file.stream(): ReadableStream
    • file.text()

参考「インスタンスメソッド - File - Web API | MDN
参考「Instance methods - Blob - Web APIs | MDN

3. その他

3.1. 任意の DOM 要素を <input type="file"> のように使う

上記の方法を用いて、任意の DOM 要素で発生したイベントハンドラからファイル選択ダイアログを表示可能なため、好きな DOM 要素を <input type="file"> の代わりにすることが出来ます。

本記事の内容と直接の関係はありませんが、<input type="file"> のスタイルを display: none; にして <label> 要素で囲むことで、<label> のクリックでイベントを発火することも可能です。

3.2. jQuery を使う

jQuery オブジェクトの click() (用途に関わらず非推奨) および trigger('click') は jQuery 上で設定されたイベントハンドラを呼ぶだけのため、要素をクリックした扱いになりません。

実際にクリックしたようにするためには HTMLElementclick() メソッドを呼ぶ必要があります。

jQueryObject[0] とすると jQuery オブジェクトから HTMLElement を得ることが出来ます。

参考「How do I pull a native DOM element from a jQuery object? | jQuery Learning Center

3.2.1. ファイルを保存する

オブジェクト URL を使う場合
const blob = new Blob(['foo\n'], { type: 'text/plain' });

$('<a>', {
	href: URL.createObjectURL(blob),
	download: 'foo.txt',
})[0].click();
データ URL を使う場合
const text = 'foo\n';

$('<a>', {
	href: 'data:text/plain,' + encodeURIComponent(text),
	download: 'foo.txt',
})[0].click();

3.2.2. ファイルを開く

$('<input type="file" accept="text/plain">').on('change', async event => {

	const files = event.target.files;

	const content = await files[0].text();
	console.log(content);

})[0].click();
67
83
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
67
83

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?