【问题标题】:Download JSON object as a file from browser从浏览器下载 JSON 对象作为文件
【发布时间】:2013-11-12 08:09:07
【问题描述】:

我有以下代码让用户下载 csv 文件中的数据字符串。

exportData = 'data:text/csv;charset=utf-8,';
exportData += 'some csv strings';
encodedUri = encodeURI(exportData);
newWindow = window.open(encodedUri);

如果客户端运行代码,它会生成空白页面并开始下载 csv 文件中的数据。

所以我尝试使用 JSON 对象来做到这一点,例如

exportData = 'data:text/json;charset=utf-8,';
exportData += escape(JSON.stringify(jsonObject));
encodedUri = encodeURI(exportData);
newWindow = window.open(encodedUri);

但我只看到一个显示 JSON 数据的页面,而不是下载它。

我进行了一些研究,this one 声称可以工作,但我看不出我的代码有什么不同。

我的代码中是否缺少某些内容?

感谢您阅读我的问题:)

【问题讨论】:

    标签: javascript json


    【解决方案1】:

    这就是我为我的应用程序解决它的方法:

    HTML: <a id="downloadAnchorElem" style="display:none"></a>

    JS(纯 JS,这里不是 jQuery):

    var dataStr = "data:text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(storageObj));
    var dlAnchorElem = document.getElementById('downloadAnchorElem');
    dlAnchorElem.setAttribute("href",     dataStr     );
    dlAnchorElem.setAttribute("download", "scene.json");
    dlAnchorElem.click();
    

    在这种情况下,storageObj 是您要存储的 js 对象,“scene.json”只是生成文件的示例名称。

    与其他提议的方法相比,此方法具有以下优点:

    • 无需点击任何 HTML 元素
    • 结果将根据您的需要命名
    • 不需要 jQuery

    我需要这种行为而无需显式点击,因为我想在某个时候从 js 自动触发下载。

    JS 解决方案(无需 HTML):

      function downloadObjectAsJson(exportObj, exportName){
        var dataStr = "data:text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(exportObj));
        var downloadAnchorNode = document.createElement('a');
        downloadAnchorNode.setAttribute("href",     dataStr);
        downloadAnchorNode.setAttribute("download", exportName + ".json");
        document.body.appendChild(downloadAnchorNode); // required for firefox
        downloadAnchorNode.click();
        downloadAnchorNode.remove();
      }
    

    【讨论】:

    • 这是唯一适用于超过 =~ 2000 个字符的数据的解决方案。因为您预先添加了数据:
    • 有人能指出我的规范或 MDN 页面,它更详细地解释了整个前置数据类型的工作原理,即。 “数据:文本/json;字符集=utf-8”?我正在使用它,但感觉就像魔术一样,阅读详细信息会很棒,但我什至不知道如何用谷歌搜索它。
    • 当您必须下载超过 2000 个字符的大文件时,这在 IE 中不起作用。
    • 不过,这不会无限制地工作。您只能下载大约 1MB 的数据。例如,var storageObj = []; for (var i=0; i<1000000; ++i) storageObj.push('aaa'); 在 Chrome 61 中给出“下载失败 - 网络错误”
    • @YASHDAVE 改用JSON.stringify(exportObj, null, 2)
    【解决方案2】:

    找到答案了。

    var obj = {a: 123, b: "4 5 6"};
    var data = "text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(obj));
    
    $('<a href="data:' + data + '" download="data.json">download JSON</a>').appendTo('#container');
    

    对我来说似乎工作得很好。

    ** 所有功劳归于@cowboy-ben-alman,他是上述代码的作者**

    【讨论】:

    • @Cybear 你能解释一下第三行吗?
    • 您需要将 data: 添加到您的 url,否则用户可能会在许多浏览器中达到 2000 个字符的限制。
    • 嘿,我知道这是一个旧答案,但是,知道这个解决方案不适用于 IE(所有这些)IE 不熟悉下载属性参考 - link
    【解决方案3】:

    您可以尝试使用:

    根本不需要处理任何 HTML 元素。

    var data = {
        key: 'value'
    };
    var fileName = 'myData.json';
    
    // Create a blob of the data
    var fileToSave = new Blob([JSON.stringify(data)], {
        type: 'application/json'
    });
    
    // Save the file
    saveAs(fileToSave, fileName);
    

    如果您想根据this answer 漂亮地打印 JSON,您可以使用:

    JSON.stringify(data,undefined,2)
    

    【讨论】:

    • saveAs() 来自 FileSaver.js - github.com/eligrey/FileSaver.js
    • “根本不需要处理任何 HTML 元素” ...并阅读 filesaver.js 的源代码 ...它确实做到了,哈哈
    • 是的。我的意思是说,不需要直接处理 HTML 元素。
    • 这是最好的答案,因为它没有 1MB 的大小限制,并且使用库而不是自定义黑客
    • FileSaver.js 对于进行简单的文件下载来说非常繁重。在下面检查我的答案; CTRL+F 并搜索“ES6+”。
    【解决方案4】:

    这将是一个纯 JS 版本(改编自牛仔的):

    var obj = {a: 123, b: "4 5 6"};
    var data = "text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(obj));
    
    var a = document.createElement('a');
    a.href = 'data:' + data;
    a.download = 'data.json';
    a.innerHTML = 'download JSON';
    
    var container = document.getElementById('container');
    container.appendChild(a);
    

    http://jsfiddle.net/sz76c083/1

    【讨论】:

    • 感谢您的回复,即使我问这个问题已经 2 年了!我更喜欢纯 JS 而不是 jQuery 语法。
    • 您需要将 data: 添加到您的 url,否则用户可能会在许多浏览器中达到 2000 个字符的限制。
    • 如何在页面加载时开始下载。每当用户浏览页面网址时,他都会提示下载
    • 今天在Edge中测试:data.json无法下载。
    【解决方案5】:

    为只针对现代浏览器的用户提供简单、干净的解决方案:

    function downloadTextFile(text, name) {
      const a = document.createElement('a');
      const type = name.split(".").pop();
      a.href = URL.createObjectURL( new Blob([text], { type:`text/${type === "txt" ? "plain" : type}` }) );
      a.download = name;
      a.click();
    }
    
    downloadTextFile(JSON.stringify(myObj), 'myObj.json');
    

    【讨论】:

    • 谢谢,只有一个没有给我尺寸问题
    【解决方案6】:

    以下对我有用:

    /* function to save JSON to file from browser
    * adapted from http://bgrins.github.io/devtools-snippets/#console-save
    * @param {Object} data -- json object to save
    * @param {String} file -- file name to save to 
    */
    function saveJSON(data, filename){
    
        if(!data) {
            console.error('No data')
            return;
        }
    
        if(!filename) filename = 'console.json'
    
        if(typeof data === "object"){
            data = JSON.stringify(data, undefined, 4)
        }
    
        var blob = new Blob([data], {type: 'text/json'}),
            e    = document.createEvent('MouseEvents'),
            a    = document.createElement('a')
    
        a.download = filename
        a.href = window.URL.createObjectURL(blob)
        a.dataset.downloadurl =  ['text/json', a.download, a.href].join(':')
        e.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null)
        a.dispatchEvent(e)
    }
    

    然后这样称呼它

    saveJSON(myJsonObject, "saved_data.json");
    

    【讨论】:

    • 虽然这是一个很好的答案,但 initMouseEvent()deprecated 网络标准,不应再使用。而是使用new MouseEvent() 接口。不过,这只是一个小重构。
    • @morkro 是正确的;我在下面发布了一个答案,该答案构建并改进了@maia 的答案,删除了initMouseEvent(并且代码通常已清理)
    【解决方案7】:

    我最近不得不创建一个按钮来下载一个包含所有大型表单值的 json 文件。我需要它来使用 IE/Edge/Chrome。这就是我所做的:

    function download(text, name, type)
        {
            var file = new Blob([text], {type: type});
            var isIE = /*@cc_on!@*/false || !!document.documentMode;
            if (isIE)
            {
                window.navigator.msSaveOrOpenBlob(file, name);
            }
            else
            {
                var a = document.createElement('a');
                a.href = URL.createObjectURL(file);
                a.download = name;
                a.click();
            }
         }
    
    download(jsonData, 'Form_Data_.json','application/json');
    

    edge 中的文件名和扩展名存在一个问题,但在撰写本文时,这似乎是应修复的 Edge 错误。

    希望这对某人有所帮助

    【讨论】:

    • 这适用于 Chrome,但似乎不适用于 Firefox...请帮助! codepen.io/anon/pen/ePYPJb
    • 不错的功能,添加document.body.appendChild(a); a.style.display = 'none';使其在Firefox中运行。
    【解决方案8】:

    2021 年的 ES6+ 版本;也没有 1MB 限制:

    这是改编自 @maia 的版本,针对现代 Javascript 进行了更新,将不推荐使用的 initMouseEvent 替换为 new MouseEvent(),并且代码总体有所改进:

    const saveTemplateAsFile = (filename, dataObjToWrite) => {
        const blob = new Blob([JSON.stringify(dataObjToWrite)], { type: "text/json" });
        const link = document.createElement("a");
    
        link.download = filename;
        link.href = window.URL.createObjectURL(blob);
        link.dataset.downloadurl = ["text/json", link.download, link.href].join(":");
    
        const evt = new MouseEvent("click", {
            view: window,
            bubbles: true,
            cancelable: true,
        });
    
        link.dispatchEvent(evt);
        link.remove()
    };
    

    如果你想传入一个对象:

    saveTemplateAsFile("filename.json", myDataObj);
    

    【讨论】:

    • 我相信你应该在完成后清理link,调用link.remove()
    • 我在离线 html/js 文件中提供下载,这对我来说比 FileSaver.js 更简单。谢谢!
    【解决方案9】:

    链接的download 属性是新的,Internet Explorer 不支持(请参阅兼容性表here)。对于这个问题的跨浏览器解决方案,我会看看FileSaver.js

    【讨论】:

      【解决方案10】:
          downloadJsonFile(data, filename: string){
              // Creating a blob object from non-blob data using the Blob constructor
              const blob = new Blob([JSON.stringify(data)], { type: 'application/json' });
              const url = URL.createObjectURL(blob);
              // Create a new anchor element
              const a = document.createElement('a');
              a.href = url;
              a.download = filename || 'download';
              a.click();
              a.remove();
            }
      

      您可以使用 Blob 轻松自动下载文件并将其传输到第一个参数 downloadJsonFile。 filename 是您要设置的文件名。

      【讨论】:

        【解决方案11】:

        React:在你的渲染方法中添加它。

        • 对象处于状态

        <a
          className="pull-right btn btn-primary"
          style={{ margin: 10 }}
          href={`data:text/json;charset=utf-8,${encodeURIComponent(
          JSON.stringify(this.state.objectToDownload)
          )}`}
          download="data.json"
        >
          DOWNLOAD DATA AS JSON
        </a>
        

        道具中的对象

        <a
          className="pull-right btn btn-primary"
          style={{ margin: 10 }}
          href={`data:text/json;charset=utf-8,${encodeURIComponent(
          JSON.stringify(this.props.objectToDownload)
          )}`}
          download="data.json"
        >
          DOWNLOAD DATA AS JSON
        </a>
        

        className 和 style 是可选的,根据需要修改样式。

        【讨论】:

          【解决方案12】:

          尝试设置另一个 MIME 类型: exportData = 'data:application/octet-stream;charset=utf-8,';

          但保存对话框中的文件名可能有问题。

          【讨论】:

          • 抱歉迟到了。我试过你的答案,它确实下载了文件,但其中包含错误的数据.. :(
          • 这对我有用...data = "data:application/octet-stream;charset=utf-8," + encodeURIComponent(JSON.stringify(data)); window.open(data); 它只是将文件下载为“下载”,但我对数据进行了字符串化,然后进行了 uri 编码。
          【解决方案13】:

          如果您更喜欢控制台 sn-p、raser,而不是文件名,您可以这样做:

          window.open(URL.createObjectURL(
              new Blob([JSON.stringify(JSON)], {
                type: 'application/binary'}
              )
          ))
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2021-10-20
            • 2011-12-19
            • 2015-04-15
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多