サーバーを介さずにユーザーがダウンロードできるようにメモリ内にファイルを作成する方法は?


824

サーバーとやり取りせずに、クライアント側でテキストファイルを作成し、ユーザーにダウンロードを促す方法はありますか?自分のマシン(セキュリティなど)に直接書き込むことができないことはわかっていますが、作成して保存するように指示できますか?


回答:


432

データURIを使用できます。ブラウザのサポートはさまざまです。ウィキペディアを参照してください。例:

<a href="data:application/octet-stream;charset=utf-16le;base64,//5mAG8AbwAgAGIAYQByAAoA">text file</a>

オクテットストリームは、ダウンロードプロンプトを強制することです。それ以外の場合は、おそらくブラウザーで開きます。

CSVの場合、次のものを使用できます。

<a href="data:application/octet-stream,field1%2Cfield2%0Afoo%2Cbar%0Agoo%2Cgai%0A">CSV Octet</a>

jsFiddleデモを試してください。


19
これはクロスブラウザソリューションではありませんが、一見の価値があります。たとえば、IEはサポートをデータURIに制限します。IE 8はサイズを32KBに制限し、IE 7以下はまったくサポートしていません。
Darin Dimitrov

8
Chromeバージョン19.0.1084.46では、このメソッドは次の警告を生成します:「リソースはドキュメントとして解釈されましたが、MIMEタイプtext / csvで転送されました: "data:text / csv、field1%2Cfield2%0Afoo%2Cbar%0Agoo%2Cgai%0A"。 」ダウンロードはトリガーされません
Chris

2
これは現在Chrome(v20とv21でテスト済み)では機能しますが、IE9では機能しません(それは単なるjsFiddleかもしれませんが、どういうわけか私は疑っています)。
イアカム

5
コードをUTF-8に変換するコードがない限り、正しい文字セットはほぼ間違いなくUTF-16です。JavaScriptは内部でUTF-16を使用します。テキストファイルまたはCSVファイルがある場合は、文字列を '\ ufeff'、UTF-16BEのバイトオーダーマークで開始します。テキストエディターは、非ASCII文字を正しく読み取ることができます。
larspars 2014年

14
適切なファイル名と拡張子を付け、OSにそれをどうするかを指示するには、download = "txt.csv"属性を追加するだけです。
elshnkhll

724

HTML5対応ブラウザ向けのシンプルなソリューション...

function download(filename, text) {
  var element = document.createElement('a');
  element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text));
  element.setAttribute('download', filename);

  element.style.display = 'none';
  document.body.appendChild(element);

  element.click();

  document.body.removeChild(element);
}
form * {
  display: block;
  margin: 10px;
}
<form onsubmit="download(this['name'].value, this['text'].value)">
  <input type="text" name="name" value="test.txt">
  <textarea name="text"></textarea>
  <input type="submit" value="Download">
</form>

使用法

download('test.txt', 'Hello world!');

10
うん。これは、@ MatthewFlaschenが3年ほど前にここ投稿したものです。
ジョセフSilber

48
はい、しかしでdownload属性ます;-)ファイル名を指定することができます
マテイPokorný


4
Chrome txtは、ファイル名に拡張子を指定しない場合にのみ拡張子を追加します。これを行うdownload("data.json", data)と、期待どおりに機能します。
カール・スミス

6
これは、Chrome(73.0.3683.86)とFirefox(66.0.2)で機能しました。IE11(11.379.17763.0)およびEdge(44.17763.1.0)では機能しませんでした。
Sam

231

上記のすべてのソリューションがすべてのブラウザで機能するわけではありません。ここで最後に(とIE 10+、FirefoxとChromeでどのような作品であることなく、 jQueryのか、他のライブラリ):

save: function(filename, data) {
    var blob = new Blob([data], {type: 'text/csv'});
    if(window.navigator.msSaveOrOpenBlob) {
        window.navigator.msSaveBlob(blob, filename);
    }
    else{
        var elem = window.document.createElement('a');
        elem.href = window.URL.createObjectURL(blob);
        elem.download = filename;        
        document.body.appendChild(elem);
        elem.click();        
        document.body.removeChild(elem);
    }
}

なお、状況によっては、 を削除しelemた後にURL.revokeObjectURLURL.createObjectURLのドキュメントによると:

createObjectURL()を呼び出すたびに、同じオブジェクトのURLがすでに作成されている場合でも、新しいオブジェクトURLが作成されます。これらは、不要になったときにURL.revokeObjectURL()を呼び出して解放する必要があります。ドキュメントがアンロードされると、ブラウザはこれらを自動的に解放します。ただし、最適なパフォーマンスとメモリ使用量を得るために、明示的にアンロードできる安全な時間がある場合は、そうする必要があります。


7
どうもありがとう。私はここにリストされているすべての例を試しましたが、これはどのブラウザーでも動作します。これは受け入れられる答えになるはずです。
LEM

Chromeでは、これを機能させるために実際に要素を本文に追加する必要はありませんでした。
JackMorrissey 2016

1
AngularJS 1.xアプリの場合は、作成時にURLの配列を作成し、コンポーネントの$ onDestroy関数でクリーンアップできます。これは私にとって非常に効果的です。
Splaktar 2016

1
他の答えはFailed: network errorChromeにつながりました。これはうまくいきます。
ジュニパー

4
これは、Chrome(73.0.3683.86)、Firefox(66.0.2)、IE11(11.379.17763.0)、およびEdge(44.17763.1.0)で機能しました。
Sam

185

上記の例はすべて、ChromeとIEでは問題なく機能しますが、Firefoxでは失敗します。アンカーをボディに追加し、クリック後に削除することを検討してください。

var a = window.document.createElement('a');
a.href = window.URL.createObjectURL(new Blob(['Test,Text'], {type: 'text/csv'}));
a.download = 'test.csv';

// Append anchor to body.
document.body.appendChild(a);
a.click();

// Remove anchor from body
document.body.removeChild(a);

4
ただし、IE 10には未解決のバグがあり(11でもまだ見ていa.click()ます)、BLOBのURLがクロスオリジンであると見なされるため、行に「アクセスが拒否されました」がスローされます。
Matt

@MattデータURIは、一部のブラウザではクロスオリジンです。私の知る限りでは、msieだけでなく、chromeでも同様です。javascriptにデータURIを挿入することでテストできます。サイトの他の部分にアクセスすることはできません...
inf3rno

7
「上記の例はすべて、ChromeとIEでは問題なく機能しますが、Firefoxでは失敗します。」回答の順序は時間の経過とともに変化する可能性があるため、これを書いたときにどの回答があなたの回答より上だったかは不明です。Firefoxで機能しないアプローチを正確に示すことはできますか?
ケビン

120

私は楽しくFileSaver.jsを使用しています。その互換性は非常によく(IE10 +とその他すべて)、使用方法は非常に簡単です。

var blob = new Blob(["some text"], {
    type: "text/plain;charset=utf-8;",
});
saveAs(blob, "thing.txt");

これはChromeでうまく機能します。ユーザーがディスク上のファイルの場所を特定できるようにするにはどうすればよいですか?
gregm 2013年

6
使いやすいライブラリに感謝します。これは簡単に最良の答えです。最近、HTML <5を使用している人々を気にしている人はいますか?
notbad.jpeg 2013年

@gregmこのプラグインであなたができるかわかりません。
Daniel Buckmaster

@gregm:ダウンロード場所ですか?これはFileSaver.jsとは関係ありません。ダウンロードの前にフォルダーを要求するようにブラウザーの構成を設定するか、でかなり新しいダウンロード属性を使用する必要があります<a>
CodeManX

1
これはIE 10+ファミリーのブラウザーに最適なソリューションです。IEはダウンロードHTML 5タグをまだサポートしていません。このページの他のソリューション(および同じ問題を説明する他のSOページ)は私にとってはうまくいきませんでした。FileSaver ftw!
TMc

22

次の方法は、IE11以降、Firefox 25以降、Chrome 30以降で機能します。

<a id="export" class="myButton" download="" href="#">export</a>
<script>
    function createDownloadLink(anchorSelector, str, fileName){
        if(window.navigator.msSaveOrOpenBlob) {
            var fileData = [str];
            blobObject = new Blob(fileData);
            $(anchorSelector).click(function(){
                window.navigator.msSaveOrOpenBlob(blobObject, fileName);
            });
        } else {
            var url = "data:text/plain;charset=utf-8," + encodeURIComponent(str);
            $(anchorSelector).attr("download", fileName);               
            $(anchorSelector).attr("href", url);
        }
    }

    $(function () {
        var str = "hi,file";
        createDownloadLink("#export",str,"file.txt");
    });

</script>

これを実際に見てください: http //jsfiddle.net/Kg7eA/

FirefoxとChromeはナビゲーション用のデータURIをサポートしています。これにより、データURIにナビゲートしてファイルを作成できますが、IEはセキュリティ上の目的でデータURIをサポートしていません。

一方、IEにはblobを保存するためのAPIがあり、ファイルの作成とダウンロードに使用できます。


私はjqueryを使用してイベント(onclickとonready)をアタッチし、属性を設定しました。これは、vanilla JSでも実行できます。コアパーツ(window.navigator.msSaveOrOpenBlob)はjqueryを必要としません。
dinesh ygv 2016年

データuriアプローチのサイズにはまだ制限がありますね。
フィル

msSaveOrOpenBlobは廃止されたとここに示されています:developer.mozilla.org/en-US/docs/Web/API/Navigator/msSaveBlob
eflat

13

このソリューションは、tiddlywiki(tiddlywiki.com)のgithubリポジトリから直接抽出されます。私はほぼすべてのブラウザーでtiddlywikiを使用しており、それは魅力のように機能します。

function(filename,text){
    // Set up the link
    var link = document.createElement("a");
    link.setAttribute("target","_blank");
    if(Blob !== undefined) {
        var blob = new Blob([text], {type: "text/plain"});
        link.setAttribute("href", URL.createObjectURL(blob));
    } else {
        link.setAttribute("href","data:text/plain," + encodeURIComponent(text));
    }
    link.setAttribute("download",filename);
    document.body.appendChild(link);
    link.click();
    document.body.removeChild(link);
}

Githubリポジトリ: セーバーモジュールのダウンロード


Chromeでは非常にうまく機能しますが、Firefoxでは機能しません。ファイルを作成してダウンロードしますが、ファイルは空です。内容はありません。何かアイデアはありますか?IEでテストされていません...
Narxx

2
関数に名前がないことを除いて、これは私のお気に入りです
Yoraco Gonzales '20

11

IE10で動作するソリューション:(csvファイルが必要でしたが、タイプとファイル名をtxtに変更するだけで十分です)

var csvContent=data; //here we load our csv data 
var blob = new Blob([csvContent],{
    type: "text/csv;charset=utf-8;"
});

navigator.msSaveBlob(blob, "filename.csv")

1
Ludovicの回答には、これだけでなく、他のブラウザーのサポートも含まれています。
Dan Dascalescu 2016年

10

文字列をダウンロードできるように変換したいだけの場合は、jQueryを使用してこれを試すことができます。

$('a.download').attr('href', 'data:application/csv;charset=utf-8,' + encodeURI(data));

1
私がコメントできるようになる前に、ここで提案されているようencodeURIとスケープデータが必要になる可能性があります:stackoverflow.com/a/32441536/4928558
atfornes

10

github.com/kennethjiang/js-file-downloadからのjs-file-downloadパッケージ、ブラウザーサポートのエッジケースを処理します。

ソースを表示を表示して、このページに記載されている手法の使用方法を確認してください。

取り付け

yarn add js-file-download
npm install --save js-file-download

使用法

import fileDownload from 'js-file-download'

// fileDownload(data, filename, mime)
// mime is optional

fileDownload(data, 'filename.csv', 'text/csv')

1
ありがとう-テスト済み-Windows上のFirefox、Chrome、Edgeで動作します
ブライアンバーンズ

8

前述のように、filesaverはクライアント側でファイルを操作するのに最適なパッケージです。しかし、大きなファイルではうまくいきません。StreamSaver.jsは、大きなファイルを処理できる代​​替ソリューション(FileServer.jsで指定)です。

const fileStream = streamSaver.createWriteStream('filename.txt', size);
const writer = fileStream.getWriter();
for(var i = 0; i < 100; i++){
    var uint8array = new TextEncoder("utf-8").encode("Plain Text");
    writer.write(uint8array);
}
writer.close()

1
Text Encoderは現在非常に実験的です。回避する(またはポリフィルする)ことをお勧めします。
Brandon.Blanchard 2017

7
var element = document.createElement('a');
element.setAttribute('href', 'data:text/text;charset=utf-8,' +      encodeURI(data));
element.setAttribute('download', "fileName.txt");
element.click();

1
このアプローチとBlobの作成の違いは何ですか?
Dan Dascalescu 2016年


5

本当に役に立った@Rickの回答に基づいています。

dataこの方法で共有したい場合は、文字列をエスケープする必要があります。

$('a.download').attr('href', 'data:application/csv;charset=utf-8,'+ encodeURI(data));

`申し訳ありませんが、StackOverflowでの私の現在の評判が低いため、@ Rickの回答にコメントすることはできません。

編集提案は共有され、拒否されました。


1
私はその提案を受け入れることができませんでした。奇妙な...私はコードを更新しました。
リック

4

URL API、特にURL.createObjectURL()を使用できますBlobエンコードへのAPIとほとんど何をダウンロードしてください。

ダウンロードが小さい場合、これは正常に動作します。

document.body.innerHTML += 
`<a id="download" download="PATTERN.json" href="${URL.createObjectURL(new Blob([JSON.stringify("HELLO WORLD", null, 2)]))}"> Click me</a>`
download.click()
download.outerHTML = ""


ダウンロードが膨大な場合は、DOMを使用する代わりに、ダウンロードパラメータを使用してリンク要素を作成し、クリックをトリガーすることをお勧めします。

link要素はドキュメントに追加されていませんが、クリックはとにかく機能します。これにより、数百ものMoのダウンロードをこの方法で作成できます。

const stack = {
 some: "stuffs",
 alot: "of them!"
}

BUTTONDOWNLOAD.onclick = (function(){
  let j = document.createElement("a")
  j.id = "download"
  j.download = "stack_"+Date.now()+".json"
  j.href = URL.createObjectURL(new Blob([JSON.stringify(stack, null, 2)]))
  j.click()
})  
<button id="BUTTONDOWNLOAD">DOWNLOAD!</button>


ボーナス!循環オブジェクトをダウンロードし、エラーを回避します

TypeError:循環オブジェクト値(Firefox)TypeError:変換

JSONへの循環構造(ChromeおよびOpera)TypeError:循環

値引数の参照はサポートされていません(エッジ)

使用する https://github.com/douglascrockford/JSON-js/blob/master/cycle.js

この例では、documentオブジェクトをjsonとしてダウンロードします。

/* JSON.decycle */
if(typeof JSON.decycle!=="function"){JSON.decycle=function decycle(object,replacer){"use strict";var objects=new WeakMap();return(function derez(value,path){var old_path;var nu;if(replacer!==undefined){value=replacer(value)}
if(typeof value==="object"&&value!==null&&!(value instanceof Boolean)&&!(value instanceof Date)&&!(value instanceof Number)&&!(value instanceof RegExp)&&!(value instanceof String)){old_path=objects.get(value);if(old_path!==undefined){return{$ref:old_path}}
objects.set(value,path);if(Array.isArray(value)){nu=[];value.forEach(function(element,i){nu[i]=derez(element,path+"["+i+"]")})}else{nu={};Object.keys(value).forEach(function(name){nu[name]=derez(value[name],path+"["+JSON.stringify(name)+"]")})}
return nu}
return value}(object,"$"))}}


document.body.innerHTML += 
`<a id="download" download="PATTERN.json" href="${URL.createObjectURL(new Blob([JSON.stringify(JSON.decycle(document), null, 2)]))}"></a>`
download.click()



2

以下の機能が動作しました。

 private createDownloadableCsvFile(fileName, content) {
   let link = document.createElement("a");
   link.download = fileName;
   link.href = `data:application/octet-stream,${content}`;
   return link;
 }

fileNameを割り当てたまま、新しいタブでファイルを開くことができますが、ダウンロードではなく、タブで開くだけですか?
Carl Kroeger Ihl

1

次の方法は、IE10 +、Edge、Opera、FF、Chromeで機能します。

const saveDownloadedData = (fileName, data) => {
    if(~navigator.userAgent.indexOf('MSIE') || ~navigator.appVersion.indexOf('Trident/')) { /* IE9-11 */
        const blob = new Blob([data], { type: 'text/csv;charset=utf-8;' });
        navigator.msSaveBlob(blob, fileName);
    } else {
        const link = document.createElement('a')
        link.setAttribute('target', '_blank');
        if(Blob !== undefined) {
            const blob = new Blob([data], { type: 'text/plain' });
            link.setAttribute('href', URL.createObjectURL(blob));
        } else {
            link.setAttribute('href', 'data:text/plain,' + encodeURIComponent(data));
        }

        ~window.navigator.userAgent.indexOf('Edge')
            && (fileName = fileName.replace(/[&\/\\#,+$~%.'':*?<>{}]/g, '_')); /* Edge */

        link.setAttribute('download', fileName);
        document.body.appendChild(link);
        link.click();
        document.body.removeChild(link);
    }
}

したがって、関数を呼び出すだけです:

saveDownloadedData('test.txt', 'Lorem ipsum');

0

私にとってこれは完璧に機能し、同じファイル名と拡張子がダウンロードされました

<a href={"data:application/octet-stream;charset=utf-16le;base64," + file64 } download={title} >{title}</a>

'title'は拡張子が付いたファイル名ですsample.pdfwaterfall.jpg、など。

'file64'は、base64のコンテンツで、次のようなものです。 Ww6IDEwNDAsIFNsaWRpbmdTY2FsZUdyb3VwOiAiR3JvdXAgQiIsIE1lZGljYWxWaXNpdEZsYXRGZWU6IDM1LCBEZW50YWxQYXltZW50UGVyY2VudGFnZTogMjUsIFByb2NlZHVyZVBlcmNlbnQ6IDcwLKCFfSB7IkdyYW5kVG90YWwiOjEwNDAsIlNsaWRpbmdTY2FsZUdyb3VwIjoiR3JvdXAgQiIsIk1lZGljYWxWaXNpdEZsYXRGZWUiOjM1LCJEZW50YWxQYXltZW50UGVyY2VudGFnZSI6MjUsIlByb2NlZHVyZVBlcmNlbnQiOjcwLCJDcmVhdGVkX0J5IjoiVGVycnkgTGVlIiwiUGF0aWVudExpc3QiOlt7IlBhdGllbnRO


0

<a></a>タグを使用してを設定しhref='path'ます。その後、<a>要素の間に画像を配置して、視覚的に確認できるようにします。必要に応じて、変更する関数を作成できますhref、同じリンクではなく動的になるようにを。

JavaScriptで<a>タグidにアクセスする場合は、タグにもを指定します。

HTMLバージョンから:

<a href="mp3/tupac_shakur-how-do-you-want-it.mp3" download id="mp3Anchor">
     <img src="some image that you want" alt="some description" width="100px" height="100px" />
</a>

今JavaScriptで:

*Create a small json file*;

const array = [
     "mp3/tupac_shakur-how-do-you-want-it.mp3",
     "mp3/spice_one-born-to-die.mp3",
     "mp3/captain_planet_theme_song.mp3",
     "mp3/tenchu-intro.mp3",
     "mp3/resident_evil_nemesis-intro-theme.mp3"
];

//load this function on window
window.addEventListener("load", downloadList);

//now create a function that will change the content of the href with every click
function downloadList() {
     var changeHref=document.getElementById("mp3Anchor");

     var j = -1;

     changeHref.addEventListener("click", ()=> {

           if(j < array.length-1) {
               j +=1;
               changeHref.href=""+array[j];
          }
           else {
               alert("No more content to download");
          }
}

-22

ファイルにテキストデータが含まれている場合、私が使用する手法は、テキストをtextarea要素に入れてユーザーに選択させ(textareaをクリックしてからCtrl + A)、コピーしてからテキストエディターに貼り付けることです。


30
私はそれを検討しましたが、使いやすさの点から、これは悲惨です。また、ファイルはCSV拡張子で保存する必要があります。それをユーザーに伝えてみてください。
ジョセフSilber
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.