Movatterモバイル変換


[0]ホーム

URL:


MDN Web Docs

このページはコミュニティーの尽力で英語から翻訳されました。MDN Web Docs コミュニティーについてもっと知り、仲間になるにはこちらから。

ウェブアプリケーションからのファイルの使用

ファイル API を使用すると、ウェブコンテンツがユーザーにローカルファイルを選択するように指示し、それらのファイルを読み取ることができるようになりました。この選択は HTML の<input type="file"> 要素を使用したり、ドラッグ & ドロップを行ったりすることで行うことができます。

選択されたファイルへのアクセス

この HTML があったとします。

html
<input type="file" multiple />

ファイル API により、ユーザーが選択したファイルを表すFile オブジェクトを含むFileList にアクセスすることができます。

multiple 属性をinput 要素に付けることで、ユーザーが複数のファイルを選択することができるようになります。

旧来の DOM セレクターを使って、最初に選択されたファイルにアクセスします。

js
const selectedFile = document.getElementById("input").files[0];

change イベントでの選択されたファイルへのアクセス

change イベントを通してFileList にアクセスすることもできます (ただし必須ではありません)。このようにEventTarget.addEventListener() を使ってchange イベントのリスナーを追加する必要があります。

js
const inputElement = document.getElementById("input");inputElement.addEventListener("change", handleFiles, false);function handleFiles() {  const fileList = this.files; /* ファイルリストを処理するコードがここに入る */}

選択されたファイルについての情報の取得

DOM が提供するFileList オブジェクトは、File オブジェクトとして指定された、ユーザーが選択したすべてのファイルをリストアップします。ファイルリストのlength 属性の値をチェックすることで、ユーザーが選択したファイルの数を知ることができます。

js
const numFiles = fileList.length;

個々のFile オブジェクトは、単に配列としてリストにアクセスするだけで取得できます。

File オブジェクトには 3 つのプロパティがあり、ファイルに関する有益な情報を得られます。

name

読み取り専用の文字列としてのファイル名。これはファイル名のみで、パスに関する情報は含まれていません。

size

読み取り専用の 64 ビット整数によるバイト単位のファイルサイズです。

type

読み取り専用の文字列としてのファイルの MIME タイプです。MIME タイプが特定できないときは空文字列 ("") となります。

例: ファイルサイズを表示

次のコードはsize プロパティを利用する例です。

html
<!doctype html><html lang="ja-JP">  <head>    <meta charset="UTF-8" />    <title>ファイルのサイズ</title>  </head>  <body>    <form name="uploadForm">      <div>        <input type="file" multiple />        <label for="fileNum">選択されたファイル:</label>        <output>0</output>;        <label for="fileSize">合計サイズ:</label>        <output>0</output>      </div>      <div><input type="submit" value="Send file" /></div>    </form>    <script>      const uploadInput = document.getElementById("uploadInput");      uploadInput.addEventListener(        "change",        () => {          // 合計サイズを計算          let numberOfBytes = 0;          for (const file of uploadInput.files) {            numberOfBytes += file.size;          }          // 最も近い接頭辞単位に近似          const units = [            "B",            "KiB",            "MiB",            "GiB",            "TiB",            "PiB",            "EiB",            "ZiB",            "YiB",          ];          const exponent = Math.min(            Math.floor(Math.log(numberOfBytes) / Math.log(1024)),            units.length - 1,          );          const approx = numberOfBytes / 1024 ** exponent;          const output =            exponent === 0              ? `${numberOfBytes} bytes`              : `${approx.toFixed(3)} ${                  units[exponent]                } (${numberOfBytes} bytes)`;          document.getElementById("fileNum").textContent =            uploadInput.files.length;          document.getElementById("fileSize").textContent = output;        },        false,      );    </script>  </body></html>

click() メソッドを使用して非表示の input 要素を使用する

見た目の悪い<input> 要素を非表示にし、独自のインターフェイスでファイル選択を開き、ユーザーが選択したファイルを表示することができます。 input 要素のスタイルをdisplay:none とし、その上でclick() メソッドを<input> に対して呼び出すことで実現できます。

次のような HTML を考えてみましょう。

html
<input  type="file"   multiple  accept="image/*"  /><button type="button">  いくつかのファイルを選択してください。</button>

click イベントを扱うコードは次のようなものです。

js
const fileSelect = document.getElementById("fileSelect");const fileElem = document.getElementById("fileElem");fileSelect.addEventListener(  "click",  (e) => {    if (fileElem) {      fileElem.click();    }  },  false,);

<button> は、好きなようにスタイル付けできます。

label 要素を使用して非表示の file input 要素を起動

JavaScript (click() メソッド) を使用せずにファイル選択を開けるようにするために、<label> 要素を使用します。この場合、 input 要素にdisplay: none (またはvisibility: hidden) を設定して非表示に設定すると、ラベルがキーボードからアクセスできなくなります。代わりに、視覚的に非表示にする手法 (visually-hidden technique) を使用します。

次の HTML を見てください。

html
<input  type="file"   multiple  accept="image/*"  /><label for="fileElem">いくつかのファイルを選択してください。</label>

そしてこの CSS です。

css
.visually-hidden {  clip: rect(0 0 0 0);  clip-path: inset(50%);  height: 1px;  overflow: hidden;  position: absolute;  white-space: nowrap;  width: 1px;}input.visually-hidden:is(:focus, :focus-within) + label {  outline: thin dotted;}

JavaScript コードを追加してfileElem.click() を呼び出す必要はありません。またこの場合は、ラベル要素のスタイルを希望どおりに設定することもできます。前例のようにアウトラインに設定したり、background-color や box-shadow を設定したりして、ラベルの非表示入力フィールドのフォーカスステータスを視覚的に示す必要があります。(この記事を書いている時点では、 Firefox は<input type="file"> 要素に対してこの視覚的な手がかりを表示していません。)

ドラッグ & ドロップを使用したファイルの選択

ユーザーがファイルをウェブアプリケーションにドラッグ & ドロップすることもできます。

最初のステップは、ドロップゾーンを確立することです。コンテンツのどの部分がドロップを受け入れるかは、アプリケーションの設計によって異なりますが、要素がドロップイベントを受け取れるようにするのは簡単です。

js
let dropbox;dropbox = document.getElementById("dropbox");dropbox.addEventListener("dragenter", dragenter, false);dropbox.addEventListener("dragover", dragover, false);dropbox.addEventListener("drop", drop, false);

この例では、IDdropbox を持つ要素をドロップゾーンに指定しています。これは、dragenterdragoverdrop の各イベントのリスナーを追加することで行われます。

実際には、この場合、dragenterdragover のイベントでは何もする必要はありませんので、これらの関数はどちらも簡単です。これらの関数はイベントの伝播を停止し、既定のアクションが発生しないようにするだけです。

js
function dragenter(e) {  e.stopPropagation();  e.preventDefault();}function dragover(e) {  e.stopPropagation();  e.preventDefault();}

本当の魔法はdrop() 関数の中で起こります。

js
function drop(e) {  e.stopPropagation();  e.preventDefault();  const dt = e.dataTransfer;  const files = dt.files;  handleFiles(files);}

ここでは、イベントからdataTransfer フィールドを取得し、そこからファイルリストを取得し、それをhandleFiles() に渡します。これより先は、ユーザーが入力要素を使用したかドラッグ & ドロップを使用するかどうかにかかわらず、ファイルの処理方法は全く同じです。

例: ユーザーが選択した画像のサムネイルを表示

次の素晴らしい写真共有サイトを開発していて、ユーザーが実際に画像をアップロードする前に HTML を使って画像のサムネイルプレビューを表示させたいとしましょう。前に説明したようにinput 要素やドロップゾーンを設定し、次のhandleFiles() のような関数を呼び出せば良いのです。

js
function handleFiles(files) {  for (let i = 0; i < files.length; i++) {    const file = files[i];    if (!file.type.startsWith("image/")) {      continue;    }    const img = document.createElement("img");    img.classList.add("obj");    img.file = file;    preview.appendChild(img); // 「プレビュー」とは、コンテンツが表示される div 出力のことを想定しています。    const reader = new FileReader();    reader.onload = (e) => {      img.src = e.target.result;    };    reader.readAsDataURL(file);  }}

ここでは、ユーザーが選択したファイルを処理するループが各ファイルのtype 属性を見て、その MIME タイプがimage/ で始まるかどうかを確認しています。画像である各ファイルに対して、新しいimg 要素を作成します。CSS は、きれいな境界線や影を設定したり、画像のサイズを指定したりするために使用しますので、ここでは必要ありません。

各画像には CSS クラスobj が追加されており、DOM ツリーで簡単に見つけることができます。また、各画像にfile 属性を追加し、画像のFile を指定しています。これにより、後で実際にアップロードする画像を取得することができます。Node.appendChild() を使用して、文書のプレビュー領域に新しいサムネイルを追加します。

次に、画像の読み込みとimg 要素へのアタッチを非同期で処理するためのFileReader を確立します。新しいFileReader オブジェクトを作成した後、そのonload 関数を設定し、readAsDataURL() を呼び出してバックグラウンドで読み込み処理を開始します。画像ファイルのコンテンツ全体が読み込まれると、それらはdata: URL に変換され、onload コールバックに渡されます。このルーチンの実装では、img 要素のsrc 属性が読み込まれた画像に設定され、その結果、画像がユーザーの画面のサムネイルに表示されます。

オブジェクト URL を利用する

DOM のURL.createObjectURL()URL.revokeObjectURL() メソッドを使用すると、ユーザーのコンピューター上のローカルファイルなど、DOMFile オブジェクトを使用して参照可能なあらゆるデータを参照するために使用できるシンプルな URL 文字列を作成できます。

HTML から URL で参照したいFile オブジェクトがある場合は、次のようにオブジェクト URL を作成します。

js
const objectURL = window.URL.createObjectURL(fileObj);

オブジェクト URL はFile オブジェクトを識別する文字列です。URL.createObjectURL() を呼び出すたびに、すでにそのファイルのオブジェクト URL を作成していても、一意のオブジェクト URL が作成されます。これらはそれぞれ解除する必要があります。これらはドキュメントがアンロードされると自動的に解放されますが、ページが動的にこれらを使用している場合はURL.revokeObjectURL() を呼び出して明示的に解放する必要があります。

js
URL.revokeObjectURL(objectURL);

例: オブジェクト URL で画像を表示

この例では、オブジェクト URL を使用して画像のサムネイルを表示しています。さらに、ファイル名やサイズなどの他のファイル情報も表示します。

インターフェイスとなる HTML は次のようになります。

html
<input  type="file"   multiple  accept="image/*"  /><a href="#">いくつかのファイルを選択してください。</a><div>  <p>ファイルが選択されていません。</p></div>

これにより、ファイル<input> 要素と、ファイル選択を呼び出すリンクが確立されます (あまり美しくないファイル入力を非表示にするため)。これは、ファイル選択を呼び出すメソッドと同様に、click() メソッドを使用して非表示の input 要素を使用するの節で説明されています。

handleFiles() メソッドは次のようになります。

js
const fileSelect = document.getElementById("fileSelect"),  fileElem = document.getElementById("fileElem"),  fileList = document.getElementById("fileList");fileSelect.addEventListener(  "click",  (e) => {    if (fileElem) {      fileElem.click();    }    e.preventDefault(); // "#" への移動を防ぐ  },  false,);fileElem.addEventListener("change", handleFiles, false);function handleFiles() {  fileList.textContent = "";  if (!this.files.length) {    const p = document.createElement("p");    p.textContent = "ファイルが選択されていません。";    fileList.appendChild(p);  } else {    const list = document.createElement("ul");    fileList.appendChild(list);    for (let i = 0; i < this.files.length; i++) {      const li = document.createElement("li");      list.appendChild(li);      const img = document.createElement("img");      img.src = URL.createObjectURL(this.files[i]);      img.height = 60;      li.appendChild(img);      const info = document.createElement("span");      info.textContent = `${this.files[i].name}: ${this.files[i].size} バイト`;      li.appendChild(info);    }  }}

これは、<div> の URL をfileList という ID で取得することから始まります。これは、サムネイルを含むファイルリストを挿入するブロックです。

handleFiles() に渡されたFileList オブジェクトが空の場合、ブロックの内部 HTML に「ファイルが選択されていません」と表示するように設定します。そうでない場合は、次のようにファイルリストの構築を開始します。

  1. 新しく順序なしリスト (<ul>) 要素を作成します。
  2. 新しいリスト要素は、<div> ブロックの中にNode.appendChild() メソッドを呼び出すことで挿入されます。
  3. files で表されるFileList 内のそれぞれのFile に対して次の処理を実行します。
    1. 新しくリストアイテム (<li>) 要素を作成し、リストに挿入します。
    2. 新しく画像 (<img>) 要素を作成します。
    3. URL.createObjectURL() を用いて、Blob の URL を作成して、画像のソースをファイルを表す新しいオブジェクト URL に設定します。
    4. 画像の高さを 60 ピクセルに設定します。
    5. 新しいリストアイテムをリストに追加する。

上のコードのライブデモはこちらです。

画像が読み込まれた直後にオブジェクト URL をすぐに取り消さないことに注意してください。そうすると、ユーザーが画像に対して操作(右クリックして画像を保存したり、新しいタブで開いたりなど)ができなくなってしまいます。長寿命のアプリケーションでは、オブジェクト URL が不要になった場合(画像が DOM から除去された場合など)に、URL.revokeObjectURL() メソッドを呼び出し、オブジェクト URL 文字列を渡して、メモリーを解放するためにオブジェクト URL を無効にする必要があります。

例: ユーザーが選択したファイルを送信

この例では、ユーザーがファイル(例えば、前回の例で使用した選択した画像)をサーバーにアップロードする方法を示します。

メモ:通常、 HTTP リクエストを行うためには、フェッチ APIXMLHttpRequest の代わりに使用することをお勧めします。ただし、この例では、ユーザーにアップロードの進行状況を表示したいのですが、この機能はフェッチ API ではまだ対応していないため、XMLHttpRequest を使用しています。

フェッチ API を使用した進行状況の通知の標準化に関する取り組みは、https://github.com/whatwg/fetch/issues/607 で行われています。

アップロードタスクの生成

前の例でサムネイルを作成したコードの続きで、すべてのサムネイル画像が CSS クラスobj にあり、対応するFilefile 属性に添付されていることを思い出してください。これにより、このようにDocument.querySelectorAll()を使用して、ユーザーがアップロードするために選択した画像をすべて選択することができます。

js
function sendFiles() {  const imgs = document.querySelectorAll(".obj");  for (let i = 0; i < imgs.length; i++) {    new FileUpload(imgs[i], imgs[i].file);  }}

document.querySelectorAll では CSS クラスがobj である文書中のすべての要素を取得します。この例では、これらの要素はすべての画像サムネイルになります。このリストを取得したら、それを参照して、それぞれの新しいFileUpload インスタンスを作成するのは簡単です。それぞれが対応するファイルのアップロードを処理します。

ファイルのアップロード処理を行う

FileUpload 関数は 2 つの入力、画像要素と画像データを読み込むファイルを受け付けます。

js
function FileUpload(img, file) {  const reader = new FileReader();  this.ctrl = createThrobber(img);  const xhr = new XMLHttpRequest();  this.xhr = xhr;  const self = this;  this.xhr.upload.addEventListener(    "progress",    (e) => {      if (e.lengthComputable) {        const percentage = Math.round((e.loaded * 100) / e.total);        self.ctrl.update(percentage);      }    },    false,  );  xhr.upload.addEventListener(    "load",    (e) => {      self.ctrl.update(100);      const canvas = self.ctrl.ctx.canvas;      canvas.parentNode.removeChild(canvas);    },    false,  );  xhr.open(    "POST",    "https://demos.hacks.mozilla.org/paul/demos/resources/webservices/devnull.php",  );  xhr.overrideMimeType("text/plain; charset=x-user-defined-binary");  reader.onload = (evt) => {    xhr.send(evt.target.result);  };  reader.readAsBinaryString(file);}function createThrobber(img) {  const throbberWidth = 64;  const throbberHeight = 6;  const throbber = document.createElement("canvas");  throbber.classList.add("upload-progress");  throbber.setAttribute("width", throbberWidth);  throbber.setAttribute("height", throbberHeight);  img.parentNode.appendChild(throbber);  throbber.ctx = throbber.getContext("2d");  throbber.ctx.fillStyle = "orange";  throbber.update = (percent) => {    throbber.ctx.fillRect(      0,      0,      (throbberWidth * percent) / 100,      throbberHeight,    );    if (percent === 100) {      throbber.ctx.fillStyle = "green";    }  };  throbber.update(0);  return throbber;}

上のFileUpload() 関数は、進捗情報を表示するための throbber を作成し、データのアップロードを処理するためのXMLHttpRequest を作成します。

実際にデータを転送する前に、いくつかの準備段階があります。

  1. XMLHttpRequest のアップロードprogress リスナーは、アップロードの進捗に応じて最新の情報に基づいて throbber が更新されるように、新しいパーセント値の情報で throbber を更新するように設定されています。
  2. XMLHttpRequest のアップロードload イベントハンドラーは、進捗インジケーターが実際に 100 % に達することを確認するために、throbber の進捗情報を 100% に更新するように設定されています (プロセス中に粒度のクセがある場合)。そして、必要がなくなれば throbber を削除します。これにより、アップロードが完了すると throbber が消えます。
  3. 画像ファイルをアップロードするリクエストは、XMLHttpRequestopen() メソッドを呼び出して POST リクエストを生成することで開始されます。
  4. アップロードの MIME タイプはXMLHttpRequest 関数のoverrideMimeType() を呼び出して設定します。この場合、一般的な MIME タイプを使用しています。用途によっては MIME タイプを設定する必要がない場合もあります。
  5. FileReader オブジェクトを使用して、ファイルをバイナリー文字列に変換します
  6. 最後に、コンテンツがロードされると、XMLHttpRequest 関数のsend() が呼び出され、ファイルのコンテンツがアップロードされます。

ファイルのアップロード処理を非同期に処理する

この例では、サーバー側で PHP を使用し、クライアント側で JavaScript を使用して、ファイルの非同期アップロードを実演しています。

php
<?phpif (isset($_FILES["myFile"])) {  // Example:  move_uploaded_file($_FILES["myFile"]["tmp_name"], "uploads/" . $_FILES["myFile"]["name"]);  exit;}?><!doctype html><html lang="ja-JP">  <head>    <meta charset="UTF-8" />    <title>dnd binary upload</title>    <script>      function sendFile(file) {        const uri = "/index.php";        const xhr = new XMLHttpRequest();        const fd = new FormData();        xhr.open("POST", uri, true);        xhr.onreadystatechange = () => {          if (xhr.readyState === 4 && xhr.status === 200) {            alert(xhr.responseText); // レスポンスを処理          }        };        fd.append("myFile", file);        // multipart/form-data のアップロードを開始する        xhr.send(fd);      }      window.onload = () => {        const dropzone = document.getElementById("dropzone");        dropzone.ondragover = dropzone.ondragenter = (event) => {          event.stopPropagation();          event.preventDefault();        };        dropzone.ondrop = (event) => {          event.stopPropagation();          event.preventDefault();          const filesArray = event.dataTransfer.files;          for (let i = 0; i < filesArray.length; i++) {            sendFile(filesArray[i]);          }        };      };    </script>  </head>  <body>    <div>      <div              >        ここにファイルをドラッグ & ドロップしてください      </div>    </div>  </body></html>

例: オブジェクト URL を使用して PDF を表示

オブジェクト URL は画像以外にも使用できます。埋め込まれた PDF ファイルや、ブラウザーで表示可能な他のリソースを表示するために使用できます。

Firefox では、 PDF が iframe 内に埋め込まれて表示されるようにするには (ダウンロードファイルとして提案されるのではなく)、pdfjs.disabled の設定をfalse に設定する必要があります。

html
<iframe></iframe>

そして、src 属性の変更点はこちらです。

js
const objURL = URL.createObjectURL(blob);const iframe = document.getElementById("viewer");iframe.setAttribute("src", objURL);// 後で:URL.revokeObjectURL(objURL);

例: 他のファイル形式でのオブジェクト URL の使用

他の形式のファイルも同じように操作できます。ここでは、アップロードされた動画をプレビューする方法を紹介します。

js
const video = document.getElementById("video");const objURL = URL.createObjectURL(blob);video.src = objURL;video.play();// 後で:URL.revokeObjectURL(objURL);

関連情報

Help improve MDN

Learn how to contribute.

This page was last modified on byMDN contributors.


[8]ページ先頭

©2009-2025 Movatter.jp