ユーザーのローカル デバイス上のファイルを選択して操作することは、ウェブで最も一般的に使用される機能の 1 つです。ユーザーは、写真の共有や税務書類の提出などの際に、ファイルを選択してサーバーにアップロードできます。また、サイトはネットワーク経由でデータを転送することなく、これらのデータを読み取って操作できます。このページでは、JavaScript を使用してファイルを操作する方法について説明します。
最新の File System Access API
File System Access API は、ユーザーのローカル システム上のファイルやディレクトリの読み取りと書き込みを行う方法を提供します。この機能は、Chrome や Edge などの Chromium ベースのほとんどのブラウザで利用できます。詳しくは、File System Access API をご覧ください。
File System Access API はすべてのブラウザと互換性がないため、browser-fs-access を使用することをおすすめします。これは、新しい API が利用可能な場合はそれを使用し、利用できない場合は以前のアプローチにフォールバックするヘルパー ライブラリです。
従来のファイル操作
このガイドでは、以前の JavaScript メソッドを使用してファイルを操作する方法について説明します。
ファイルを選択
ファイルを選択する方法は、HTML 入力要素を使用する方法と、ドラッグ&ドロップ ゾーンを使用する方法の 2 つが主な方法です。
HTML 入力要素
ユーザーがファイルを選択する最も簡単な方法は、主要なブラウザすべてでサポートされている <input type="file">
要素を使用することです。クリックすると、オペレーティング システムの組み込みファイル選択 UI を使用して、ファイルを選択できます。multiple
属性が含まれている場合は、複数のファイルを選択できます。ユーザーが 1 つまたは複数のファイルの選択を完了すると、要素の change
イベントが発火します。FileList
オブジェクトである event.target.files
から、ファイルのリストにアクセスできます。FileList
の各項目は File
オブジェクトです。
<!-- The `multiple` attribute lets users select multiple files. -->
<input type="file" id="file-selector" multiple>
<script>
const fileSelector = document.getElementById('file-selector');
fileSelector.addEventListener('change', (event) => {
const fileList = event.target.files;
console.log(fileList);
});
</script>
次の例では、ユーザーがオペレーティング システムの組み込みファイル選択 UI を使用して複数のファイルを選択し、選択した各ファイルをコンソールに記録します。
ユーザーが選択できるファイルの種類を制限する
場合によっては、ユーザーが選択できるファイルの種類を制限したいことがあります。たとえば、画像編集アプリは画像のみを受け付け、テキスト ファイルは受け付けません。ファイル形式の制限を設定するには、入力要素に accept
属性を追加して、受け入れられるファイル形式を指定します。
<input type="file" id="file-selector" accept=".jpg, .jpeg, .png">
カスタムのドラッグ&ドロップ
一部のブラウザでは、<input type="file">
要素はドロップ ターゲットにもなり、ユーザーがファイルをアプリにドラッグ&ドロップできます。ただし、このドロップ ターゲットは小さく、使いにくい場合があります。代わりに、<input type="file">
要素を使用してコア機能を指定した後、大きなカスタムのドラッグ&ドロップ サーフェスを指定できます。
ドロップ ゾーンを選択する
ドロップ サーフェスは、アプリケーションの設計によって異なります。ウィンドウの一部のみをドロップ サーフェスにしたい場合でも、ウィンドウ全体を使用できます。

画像圧縮アプリ Squoosh では、ユーザーが画像をウィンドウの任意の場所にドラッグし、[画像を選択] をクリックして <input type="file">
要素を呼び出すことができます。ドロップ ゾーンとして選択したものが、ユーザーがファイルをそのサーフェスにドラッグできることを明確に示していることを確認してください。
ドロップ ゾーンを定義する
要素をドラッグ&ドロップ ゾーンとして有効にするには、dragover
と drop
の 2 つのイベントのリスナーを作成します。dragover
イベントは、ドラッグ&ドロップ操作でファイルのコピーが作成されることを視覚的に示すようにブラウザの UI を更新します。drop
イベントは、ユーザーがファイルをサーフェスにドロップした後に発生します。入力要素と同様に、FileList
オブジェクトである event.dataTransfer.files
からファイルのリストにアクセスできます。FileList
の各項目は File
オブジェクトです。
const dropArea = document.getElementById('drop-area');
dropArea.addEventListener('dragover', (event) => {
event.stopPropagation();
event.preventDefault();
// Style the drag-and-drop as a "copy file" operation.
event.dataTransfer.dropEffect = 'copy';
});
dropArea.addEventListener('drop', (event) => {
event.stopPropagation();
event.preventDefault();
const fileList = event.dataTransfer.files;
console.log(fileList);
});
event.stopPropagation()
と event.preventDefault()
は、ブラウザのデフォルトの動作を停止し、代わりにコードを実行します。これがないと、ブラウザはページから移動し、ユーザーがブラウザ ウィンドウにドロップしたファイルを開きます。
ライブ デモについては、カスタムのドラッグ&ドロップをご覧ください。
ディレクトリはどうですか?
残念ながら、JavaScript を使用してディレクトリにアクセスする良い方法はありません。
<input type="file">
要素の webkitdirectory
属性を使用すると、ユーザーは 1 つまたは複数のディレクトリを選択できます。Android 版 Firefox と iOS 版 Safari を除くほとんどの主要ブラウザでサポートされています。
ドラッグ&ドロップが有効になっている場合、ユーザーがディレクトリをドロップ ゾーンにドラッグしようとする可能性があります。ドロップ イベントが発生すると、ディレクトリの File
オブジェクトが含まれますが、ディレクトリ内のファイルへのアクセスは提供されません。
ファイル メタデータを読み取る
File
オブジェクトには、ファイルに関するメタデータが含まれます。ほとんどのブラウザは、ファイル名、ファイルサイズ、MIME タイプを提供しますが、プラットフォームによっては、ブラウザによって提供される情報が異なったり、追加情報が提供されたりする場合があります。
function getMetadataForFileList(fileList) {
for (const file of fileList) {
// Not supported in Safari for iOS.
const name = file.name ? file.name : 'NOT SUPPORTED';
// Not supported in Firefox for Android or Opera for Android.
const type = file.type ? file.type : 'NOT SUPPORTED';
// Unknown cross-browser support.
const size = file.size ? file.size : 'NOT SUPPORTED';
console.log({file, name, type, size});
}
}
この動作は、input-type-file
デモで確認できます。
ファイルの内容を読み取る
FileReader
を使用して、File
オブジェクトのコンテンツをメモリに読み取ります。FileReader
に、ファイルを配列バッファ、データ URL、またはテキストとして読み取るよう指示できます。
function readImage(file) {
// Check if the file is an image.
if (file.type && !file.type.startsWith('image/')) {
console.log('File is not an image.', file.type, file);
return;
}
const reader = new FileReader();
reader.addEventListener('load', (event) => {
img.src = event.target.result;
});
reader.readAsDataURL(file);
}
この例では、ユーザーが指定した File
を読み取り、データ URL に変換して、そのデータ URL を使用して img
要素に画像を表示します。ユーザーが画像ファイルを選択したことを確認する方法については、read-image-file
のデモを参照してください。
ファイル読み取りの進行状況をモニタリングする
大きなファイルを読み取る場合は、読み取りの進行状況をユーザーに伝える UX を提供すると便利です。そのためには、FileReader
が提供する progress
イベントを使用します。progress
イベントには、loaded
(読み取られた量)と total
(読み取る量)の 2 つのプロパティがあります。
function readFile(file) {
const reader = new FileReader();
reader.addEventListener('load', (event) => {
const result = event.target.result;
// Do something with result
});
reader.addEventListener('progress', (event) => {
if (event.loaded && event.total) {
const percent = (event.loaded / event.total) * 100;
console.log(`Progress: ${Math.round(percent)}`);
}
});
reader.readAsDataURL(file);
}
ヒーロー画像: Unsplash の Vincent Botta