在内存中创建一个文件供用户下载,而不是通过服务器

Jos*_*ber 775 javascript web-applications file client-side

有没有办法在客户端创建文本文件并提示用户下载它,而不与服务器进行任何交互?我知道我不能直接写入他们的机器(安全性和所有),但是我可以创建并提示他们保存它吗?

Mat*_*rný 680

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);
}
Run Code Online (Sandbox Code Playgroud)
form * {
  display: block;
  margin: 10px;
}
Run Code Online (Sandbox Code Playgroud)
<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>
Run Code Online (Sandbox Code Playgroud)

用法

download('test.txt', 'Hello world!');
Run Code Online (Sandbox Code Playgroud)

  • 是的,但是使用`download`属性可以指定文件名;-) (47认同)
  • 是的.这正是@MatthewFlaschen [大约3年前发布的](http://stackoverflow.com/questions/3665115/create-a-file-in-memory-for-user-to-download-not-through-服务器/ 18197341?noredirect = 1#答案-3665147). (10认同)
  • 如果您没有在文件名中提供扩展名,Chrome只会附加`txt`扩展名.如果你``download("data.json",数据)`它将按预期工作. (4认同)
  • 这在Chrome(73.0.3683.86)和Firefox(66.0.2)中对我有用。它在IE11(11.379.17763.0)和Edge(44.17763.1.0)中没有工作。 (3认同)
  • 这在 Chrome 下不再有效。显然是出于安全原因。错误消息为“未捕获 DOMException:无法从“窗口”读取“localStorage”属性:文档已沙箱化且缺少“允许相同来源”标志。” (3认同)
  • 正如@earcam 已经指出的[在上面的评论中](http://stackoverflow.com/questions/3665115/create-a-file-in-memory-for-user-to-download-not-through-server/ 18197341?noredirect=1#comment-16342145)。 (2认同)
  • 无需将元素附加到 DOM。 (2认同)
  • @sean 是对的,删除 `document.body.appendChild(element);` 和 `document.body.removeChild(element);` 也同样有效。 (2认同)

Mat*_*hen 416

您可以使用数据URI.浏览器支持各不相 看维基百科.例:

<a href="data:application/octet-stream;charset=utf-16le;base64,//5mAG8AbwAgAGIAYQByAAoA">text file</a>
Run Code Online (Sandbox Code Playgroud)

八位字节流是强制下载提示.否则,它可能会在浏览器中打开.

对于CSV,您可以使用:

<a href="data:application/octet-stream,field1%2Cfield2%0Afoo%2Cbar%0Agoo%2Cgai%0A">CSV Octet</a>
Run Code Online (Sandbox Code Playgroud)

试试jsFiddle演示.

  • 这不是一个跨浏览器的解决方案,但绝对值得一看.例如,IE限制对数据uri的支持.IE 8将大小限制为32KB,IE 7及更低版本根本不支持. (16认同)
  • 只需添加download ="txt.csv"属性即可拥有正确的文件名和扩展名,并告诉您的操作系统如何处理它. (11认同)
  • 在Chrome版本19.0.1084.46中,此方法会生成以下警告:"资源被解释为文档但使用MIME类型text/csv传输:"data:text/csv,field1%2Cfield2%0Afoo%2Cbar%0Agoo%2Cgai%0A". " 不会触发下载 (8认同)
  • 正确的字符集几乎肯定是UTF-16,除非您将代码转换为UTF-8.JavaScript在内部使用UTF-16.如果您有文本或CSV文件,请使用'\ ufeff',UTF-16BE的字节顺序标记开始字符串,文本编辑器将能够正确读取非ASCII字符. (5认同)
  • 它现在在Chrome中运行(针对v20和v21测试)但不是IE9(可能只是jsFiddle,但不知何故我怀疑它). (2认同)
  • 在Safari(7.0.4)中根本不起作用.此外,从Chrome 36.0.1985.97测试版开始,似乎无法使用download属性命名文件. (2认同)

Lud*_*ltz 205

以上所有解决方案都不适用于所有浏览器.以下是最终适用于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);
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,根据您的具体情况,您可能还希望在删除后调用URL.revokeObjectURLelem.根据URL.createObjectURL的文档:

每次调用createObjectURL()时,即使您已经为同一个对象创建了一个对象URL,也会创建一个新的对象URL.必须通过在不再需要URL.revokeObjectURL()时调用其中的每一个来释放它们.浏览器将在卸载文档时自动释放这些内容; 但是,为了获得最佳性能和内存使用情况,如果有明确卸载它们的安全时间,则应该这样做.

  • 太感谢了.我已经尝试了这里列出的所有示例,只有这一个适用于任何浏览器.这应该是公认的答案. (7认同)
  • 对于那些希望避免 URL 上的垃圾收集或奇怪行为的人,只需像这样声明您的 blob:`const url = URL.createObjectURL(blob, { oneTimeOnly: true })`。如果需要,您可以随时保存 blob 并稍后生成新的 URL。 (5认同)
  • 如果您想避免任何潜在的视觉故障,请考虑在 `document.body.appendChild(elem);` 之前添加 `elem.style.display = 'none';` (5认同)
  • 其他答案导致 Chrome 中出现“失败:网络错误”。这个效果很好。 (3认同)
  • 这对我来说适用于Chrome(73.0.3683.86),Firefox(66.0.2),IE11(11.379.17763.0)和Edge(44.17763.1.0)。 (3认同)
  • 对于 AngularJS 1.x 应用程序,您可以在创建 URL 时构建一个 URL 数组,然后在组件的 $onDestroy 函数中清理它们。这对我来说非常有用。 (2认同)
  • 什么是数据?是`encodeURI(content)`吗? (2认同)

nar*_*ren 178

所有上述示例在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);
Run Code Online (Sandbox Code Playgroud)

  • "以上所有示例在chrome和IE中都运行良好,但在Firefox中失败了." 由于答案的顺序可能会随着时间的推移而改变,因此当您编写此答案时,不清楚哪些答案高于您的答案.你能准确指出哪些方法在Firefox中不起作用? (6认同)
  • 但是:[IE 10中存在一个漏洞(我在11中仍然看到它)](https://connect.microsoft.com/IE/feedback/details/797361/ie-10-treats-blob-url -as-cross-origin-and-denies-access)在`a.click()`行上抛出"access is denied",因为它认为blob URL是跨域的. (4认同)
  • 这种 blob 方法对于非常大的文件效果更好。 (2认同)

Dan*_*ter 112

我很高兴使用FileSaver.js.它的兼容性非常好(IE10 +和其他所有东西),使用起来非常简单:

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

  • 哇,谢谢你这个易于使用的库.这很容易就是最好的答案,谁在乎这些天使用HTML <5的人呢? (6认同)

Ste*_*333 45

使用斑点

function download(content, mimeType, filename){
  const a = document.createElement('a') // Create "a" element
  const blob = new Blob([content], {type: mimeType}) // Create a blob (file-like object)
  const url = URL.createObjectURL(blob) // Create an object URL from blob
  a.setAttribute('href', url) // Set "a" element link
  a.setAttribute('download', filename) // Set download filename
  a.click() // Start downloading
}
Run Code Online (Sandbox Code Playgroud)

所有现代浏览器都支持 Blob。
Caniuse 对 Blob 的支持表:

这是一个小提琴

这里是MDN 文档

Blob 对象代表一个 blob,它是不可变的原始数据的类似文件的对象;它们可以读取为文本或二进制数据......


din*_*ygv 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>
Run Code Online (Sandbox Code Playgroud)

在行动中看到这个:http://jsfiddle.net/Kg7eA/

Firefox和Chrome支持用于导航的数据URI,这允许我们通过导航到数据URI来创建文件,而IE出于安全目的不支持它.

另一方面,IE具有用于保存blob的API,可用于创建和下载文件.


NVR*_*VRM 13

我们可以使用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 = ""
Run Code Online (Sandbox Code Playgroud)


如果你的下载量很大,而不是使用 DOM,更好的方法是使用下载参数创建一个链接元素,并触发点击。

请注意,链接元素没有附加到文档中,但无论如何点击都有效!可以通过这种方式创建数百个 Mo 的下载。

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

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


奖金!下载任何循环对象,避免错误:

类型错误:循环对象值 (Firefox) 类型错误:正在转换

JSON 的循环结构(Chrome 和 Opera) TypeError: Circular

不支持值参数中的引用(边缘)

使用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()
Run Code Online (Sandbox Code Playgroud)

  • 最好且易于使用的解决方案!谢谢 (3认同)

Dan*_*515 12

此解决方案直接从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);
}
Run Code Online (Sandbox Code Playgroud)

Github repo: 下载保护程序模块

  • 除了该功能没有名称,这是我的最爱 (2认同)

Dza*_*rek 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")
Run Code Online (Sandbox Code Playgroud)

  • [Ludovic的答案](http://stackoverflow.com/questions/3665115/create-a-file-in-memory-for-user-to-download-not-through-server/33542499#33542499)包括这个大的,加上对其他浏览器的支持。 (2认同)

Ric*_*ick 10

如果您只想将字符串转换为可供下载,可以使用jQuery尝试.

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

  • 在发表评论之前,可能需要使用encodeURI的Scape数据:http://stackoverflow.com/a/32441536/4928558 (2认同)

小智 7

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

  • 这种方法和创建 Blob 有什么区别? (2认同)

Mos*_*afa 7

如前所述,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()
Run Code Online (Sandbox Code Playgroud)


Bea*_*ith 7

该包的js文件下载github.com/kennethjiang/js-file-download手柄边缘的情况下对浏览器的支持:

查看源代码以查看其如何使用此页面上提到的技术。

安装

yarn add js-file-download
npm install --save js-file-download
Run Code Online (Sandbox Code Playgroud)

用法

yarn add js-file-download
npm install --save js-file-download
Run Code Online (Sandbox Code Playgroud)

  • 谢谢 - 刚刚测试 - 适用于 Windows 上的 Firefox、Chrome 和 Edge (2认同)

pra*_*vin 5

截至2014年4月,FileSytem API可能未在W3C中标准化.我想,任何用blob查看解决方案的人都应该小心谨慎.

HTML5摇摇欲坠

FileSytem API上的W3C邮件列表


atf*_*nes 5

根据@Rick的答案,这真的很有帮助.

data如果你想以这种方式分享它,你必须scape字符串:

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

"抱歉,由于我目前在StackOverflow中的声誉很低,我无法对@ Rick的答案发表评论.

一个编辑的建议是共享和拒绝.

  • 我无法接受这个建议。奇怪...我更新了代码。 (2认同)

pix*_*ker 5

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);
}



// Start file download.
download("hello.txt","This is the content of my file :)");
Run Code Online (Sandbox Code Playgroud)

原文:https : //ourcodeworld.com/articles/read/189/how-to-create-a-file-and-generate-a-download-with-javascript-in-the-browser-without-a-server