リンクなしのJavaScript blobファイル名


189

window.locationから強制的にダウンロードする場合、JavaScriptでblobファイルの名前をどのように設定しますか?

function newFile(data) {
    var json = JSON.stringify(data);
    var blob = new Blob([json], {type: "octet/stream"});
    var url  = window.URL.createObjectURL(blob);
    window.location.assign(url);
}

上記のコードを実行すると、次のようなページ更新なしでファイルが瞬時にダウンロードされます。

bfefe410-8d9c-4883-86c5-d76c50a24a1d

代わりに、ファイル名をmy-download.jsonに設定します。

回答:


312

私が知っている唯一の方法はFileSaver.jsで使用されるトリックです

  1. 非表示の<a>タグを作成します。
  2. そのhref属性をblobのURLに設定します。
  3. そのdownload属性をファイル名に設定します。
  4. <a>タグをクリックします。

以下は簡単な例です(jsfiddle):

var saveData = (function () {
    var a = document.createElement("a");
    document.body.appendChild(a);
    a.style = "display: none";
    return function (data, fileName) {
        var json = JSON.stringify(data),
            blob = new Blob([json], {type: "octet/stream"}),
            url = window.URL.createObjectURL(blob);
        a.href = url;
        a.download = fileName;
        a.click();
        window.URL.revokeObjectURL(url);
    };
}());

var data = { x: 42, s: "hello, world", d: new Date() },
    fileName = "my-download.json";

saveData(data, fileName);

この例は、アイデアを説明するためだけに作成しました。本番用コードでは、代わりにFileSaver.jsを使用してください。

ノート

  • 古いブラウザはHTML5の一部であるため、「download」属性をサポートしていません。
  • 一部のファイル形式はブラウザによって安全でないと見なされ、ダウンロードが失敗します。txt拡張子の付いたJSONファイルを保存すると、うまくいきます。

2
@AshBlue「download」属性にはHTML5が必要です。私のコードは一例にすぎません。FileSaver.jsデモページを試すこともできます。eligrey.com
kol

1
興味深いことに、この方法で(jsfiddle.netの[実行]ボタンを何度も押して)txtを繰り返しダウンロードしようとすると、ダウンロードが失敗することがあります。
kol 2013年

2
このソリューションは、特定のしきい値を超えるサイズのファイルには機能しないことをお伝えしておきます。例:クロム用に2 MB。このサイズはブラウザごとに異なります。
manojadams

3
新しいタブでファイルを開く必要があるため、これは機能しません。ChromeでPDFを表示する必要がありますが、URLツールバーにユーザーフレンドリ名を表示する必要があります。ユーザーがダウンロードアイコンからダウンロードする場合は、同じユーザーフレンドリ名をファイルに追加する必要があります。
エイドリアンパレデス

1
追加するだけで、これを機能させるためにaタグを実際に本体にマウントする必要はありません(Chromeで今すぐ試してみ
ます

52

私はInternet Explorer(とにかく最新のバージョン)のサポートで受け入れられた回答を拡張し、jQueryを使用してコードを整理したいと思っただけです。

$(document).ready(function() {
    saveFile("Example.txt", "data:attachment/text", "Hello, world.");
});

function saveFile (name, type, data) {
    if (data !== null && navigator.msSaveBlob)
        return navigator.msSaveBlob(new Blob([data], { type: type }), name);
    var a = $("<a style='display: none;'/>");
    var url = window.URL.createObjectURL(new Blob([data], {type: type}));
    a.attr("href", url);
    a.attr("download", name);
    $("body").append(a);
    a[0].click();
    window.URL.revokeObjectURL(url);
    a.remove();
}

これがFiddleの例です。ゴッドスピード


完璧に働きました。
N8allan

1
承認されたソリューションを使用しましたが、Firefoxでは機能しませんでした。理由はまだわかりません。あなたのソリューションはFirefoxで動作しました。ありがとう。
elahehab

@elahehab私のソリューションは常に機能します;)
アレクサンドル

27

上記のソリューションと同じ原理。しかし、Firefox 52.0(32ビット)で大きなファイル(> 40 MBytes)がランダムな位置で切り捨てられるという問題がありました。revokeObjectUrl()の呼び出しを再スケジュールすると、この問題が修正されます。

function saveFile(blob, filename) {
  if (window.navigator.msSaveOrOpenBlob) {
    window.navigator.msSaveOrOpenBlob(blob, filename);
  } else {
    const a = document.createElement('a');
    document.body.appendChild(a);
    const url = window.URL.createObjectURL(blob);
    a.href = url;
    a.download = filename;
    a.click();
    setTimeout(() => {
      window.URL.revokeObjectURL(url);
      document.body.removeChild(a);
    }, 0)
  }
}

jsfiddleの例


1
このsetTimeout()ハックにより、ファイルがまったくダウンロードされないMS Edgeが修正されることがわかりました。ただし、遅延する必要があるのは、revokeObjectURL()の呼び出しのみです。
ラッセルフィリップス

「if(window.navigator.msSaveOrOpenBlob)」が私にとってのトリックであることがわかりました
Jacques Olivier

23

遅くなりましたが、同じ問題があったため、解決策を追加しました。

function newFile(data, fileName) {
    var json = JSON.stringify(data);
    //IE11 support
    if (window.navigator && window.navigator.msSaveOrOpenBlob) {
        let blob = new Blob([json], {type: "application/json"});
        window.navigator.msSaveOrOpenBlob(blob, fileName);
    } else {// other browsers
        let file = new File([json], fileName, {type: "application/json"});
        let exportUrl = URL.createObjectURL(file);
        window.location.assign(exportUrl);
        URL.revokeObjectURL(exportUrl);
    }
}

5
@benに感謝します。これは正常に動作しています。DOM要素はありません。クリックイベントのようにトリガーすることはできません。それは適切な拡張機能で素晴らしい働きをします。ただし、指定されたファイル名は考慮されず、「<myfileName> .csv」の代わりに「<object_url_id> .csv」をダウンロードします
Ram Babu S

3
FirefoxでrevokeObjectURLafterを呼び出すとlocation.assign問題なく動作しますが、Chromeでのダウンロードは中断されます。
Fred

「EdgeはFileコンストラクタをサポートしていません。」参照 caniuse.com/#feat=fileapi
user1477388

これが正解です。DOMツリーで不要なオブジェクトを作成しても意味がない
Luiz Felipe


6
saveFileOnUserDevice = function(file){ // content: blob, name: string
        if(navigator.msSaveBlob){ // For ie and Edge
            return navigator.msSaveBlob(file.content, file.name);
        }
        else{
            let link = document.createElement('a');
            link.href = window.URL.createObjectURL(file.content);
            link.download = file.name;
            document.body.appendChild(link);
            link.dispatchEvent(new MouseEvent('click', {bubbles: true, cancelable: true, view: window}));
            link.remove();
            window.URL.revokeObjectURL(link.href);
        }
    }

新しいウィンドウで開く方法はありますか?
Enrique Altuna

link.click()マウスイベントをディスパッチする代わりに呼び出すことができると思います。
Fred

2

URLから猫の写真を「cat.jpg」として保存するためのダウンロードボタンの使用

HTML:

<button onclick="downloadUrl('https://i.imgur.com/AD3MbBi.jpg', 'cat.jpg')">Download</button>

JavaScript:

function downloadUrl(url, filename) {
  let xhr = new XMLHttpRequest();
  xhr.open("GET", url, true);
  xhr.responseType = "blob";
  xhr.onload = function(e) {
    if (this.status == 200) {
      const blob = this.response;
      const a = document.createElement("a");
      document.body.appendChild(a);
      const blobUrl = window.URL.createObjectURL(blob);
      a.href = blobUrl;
      a.download = filename;
      a.click();
      setTimeout(() => {
        window.URL.revokeObjectURL(blobUrl);
        document.body.removeChild(a);
      }, 0);
    }
  };
  xhr.send();
}

1

window.location.assignが機能しませんでした。正常にダウンロードされますが、WindowsプラットフォームではCSVファイルの拡張子なしでダウンロードされます。以下は私のために働いた。

    var blob = new Blob([csvString], { type: 'text/csv' });
    //window.location.assign(window.URL.createObjectURL(blob));
    var link = window.document.createElement('a');
    link.href = window.URL.createObjectURL(blob);
    // Construct filename dynamically and set to link.download
    link.download = link.href.split('/').pop() + '.' + extension; 
    document.body.appendChild(link);
    link.click();
    document.body.removeChild(link);

0

これが私の解決策です。私の観点から、あなたはバイパスすることはできません<a>

function export2json() {
  const data = {
    a: '111',
    b: '222',
    c: '333'
  };
  const a = document.createElement("a");
  a.href = URL.createObjectURL(
    new Blob([JSON.stringify(data, null, 2)], {
      type: "application/json"
    })
  );
  a.setAttribute("download", "data.json");
  document.body.appendChild(a);
  a.click();
  document.body.removeChild(a);
}
<button onclick="export2json()">Export data to json file</button>

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.