ดาวน์โหลดวัตถุ JSON เป็นไฟล์จากเบราว์เซอร์


144

ฉันมีรหัสต่อไปนี้เพื่อให้ผู้ใช้ดาวน์โหลดสตริงข้อมูลในไฟล์ 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 แสดงอยู่เท่านั้นไม่ดาวน์โหลด

ฉันผ่านการวิจัยบางอย่างและอันนี้อ้างว่าทำงานได้ แต่ฉันไม่เห็นความแตกต่างกับรหัสของฉัน

ฉันทำอะไรบางอย่างในรหัสของฉัน?

ขอบคุณที่อ่านคำถามของฉัน :)

คำตอบ:


257

นี่คือวิธีที่ฉันแก้ไขสำหรับใบสมัครของฉัน:

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

3
นี่เป็นทางออกเดียวที่สามารถทำงานกับข้อมูลได้มากกว่า = ~ 2000 ตัว เพราะคุณได้เตรียมข้อมูลไว้แล้ว:
rjurney

1
ใครบางคนสามารถชี้ให้ฉันไปที่หน้าข้อมูลจำเพาะหรือ MDN ที่อธิบายในรายละเอียดเพิ่มเติมว่าการทำงานของข้อมูลชนิดที่ได้รับการเติมเต็มทั้งหมดนี้เป็นอย่างไร "ข้อมูล: ข้อความ / JSON; charset = UTF-8"? ฉันใช้สิ่งนี้ แต่รู้สึกเหมือนเวทมนต์จะดีมากหากได้อ่านรายละเอียด แต่ฉันไม่รู้วิธีใช้ google เพื่อมัน
sidewinderguy

1
สิ่งนี้ไม่ทำงานใน IE แม้ว่าคุณจะต้องดาวน์โหลดไฟล์ขนาดใหญ่ที่มีอักขระมากกว่า 2000
user388969

12
สิ่งนี้จะไม่ทำงานโดยไม่มีข้อ จำกัด คุณสามารถดาวน์โหลดข้อมูลได้ประมาณ 1MB เท่านั้น ตัวอย่างเช่นvar storageObj = []; for (var i=0; i<1000000; ++i) storageObj.push('aaa');ให้ "ดาวน์โหลดล้มเหลว - เครือข่ายผิดพลาด" ใน Chrome 61
oseiskar

1
@YASHDAVE ใช้JSON.stringify(exportObj, null, 2)แทน
TryingToImprove

40

พบคำตอบ

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 คุณสามารถอธิบายบรรทัดที่สามให้ฉันได้ไหม
ราหุล Khatri

คุณจะต้องการเพิ่มข้อมูล: ไปยัง url ของคุณมิฉะนั้นผู้ใช้มีแนวโน้มที่จะมีขีด จำกัด อักขระสูงสุด 2000 ตัวในเบราว์เซอร์จำนวนมาก
rjurney

เฮ้ฉันรู้ว่ามันเป็นคำตอบเก่า แต่รู้ว่าวิธีนี้ใช้ไม่ได้กับ IE (ทั้งหมดนี้) IE ไม่คุ้นเคยกับการอ้างอิงคุณสมบัติดาวน์โหลด - ลิงค์
Ayalon Grinfeld

25

นี่จะเป็นรุ่น 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


3
ขอบคุณสำหรับการตอบสนองแม้หลังจาก 2 ปีแล้วตั้งแต่ฉันถามคำถามนี้! ฉันชอบ JS บริสุทธิ์มากกว่าไวยากรณ์ jQuery
ยูจีนยู

คุณจะต้องการเสริมข้อมูล: ไปยัง url ของคุณมิฉะนั้นผู้ใช้มีแนวโน้มที่จะมีขีด จำกัด อักขระสูงสุด 2000 ตัวในเบราว์เซอร์จำนวนมาก
rjurney

ฉันจะทำให้การดาวน์โหลดนี้เริ่มต้นในการโหลดหน้าเว็บได้อย่างไร เมื่อใดก็ตามที่ผู้ใช้เรียกดู URL หน้าเขาจะได้รับแจ้งให้ดาวน์โหลด
388969

1
การทดสอบในวันนี้ใน Edge: data.json ไม่สามารถดาวน์โหลดได้
ซาร่าห์ต้นไม้

25

คุณสามารถลองใช้:

  • Blobของ JavaScript API ดั้งเดิม Constructorและ
  • FileSaver.js saveAs()วิธี

ไม่จำเป็นต้องจัดการกับองค์ประกอบ 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',
    name: fileName
});

// Save the file
saveAs(fileToSave, fileName);

หากคุณต้องการพิมพ์ JSON ให้สวยตามคำตอบนี้คุณสามารถใช้:

JSON.stringify(data,undefined,2)

1
saveAs () มาจาก FileSaver.js - github.com/eligrey/FileSaver.js
Gautham

1
"ไม่จำเป็นต้องจัดการกับองค์ประกอบ HTML ใด ๆ เลย" ... และอ่านซอร์สโค้ดของ filesaver.js ... มันทำอย่างนั้น lol
War

1
ใช่. ฉันหมายถึงไม่จำเป็นต้องจัดการกับองค์ประกอบ HTML โดยตรง
Gautham

3
นี่เป็นคำตอบที่ดีที่สุดเพราะมันมีขนาดไม่เกิน 1MB และใช้
ไลบรารี่

โหวตขึ้นสำหรับการอ้างอิง FileSaver ทำงานได้อย่างสมบูรณ์แบบ
นูน

15

การทำงานต่อไปนี้สำหรับฉัน:

/* 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");

3
แม้ว่านี่จะเป็นคำตอบที่ดี แต่initMouseEvent()เป็นมาตรฐานเว็บที่เลิกใช้แล้วและไม่ควรใช้อีกต่อไป ใช้new MouseEvent()อินเตอร์เฟสแทน มันเป็นเพียงแค่ตัวดัดแปลงเล็กน้อย
morkro

10

ฉันเพิ่งต้องสร้างปุ่มที่จะดาวน์โหลดไฟล์ 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 ที่จะต้องแก้ไข

หวังว่านี่จะช่วยใครซักคน


สิ่งนี้ใช้ได้กับ Chrome แต่ดูเหมือนจะไม่ทำงานบน Firefox ... โปรดช่วยด้วย! codepen.io/anon/pen/ePYPJb
Urmil Parikh

1
ฟังก์ชั่นดีเพิ่มdocument.body.appendChild(a); a.style.display = 'none';เพื่อให้มันทำงานใน Firefox
Fabian von Ellerts

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

ขอขอบคุณหนึ่งเดียวที่ไม่ให้ปัญหาเรื่องขนาดกับฉันเลย
Roelant

4

downloadคุณสมบัติของการเชื่อมโยงใหม่และไม่ได้รับการสนับสนุนใน Internet Explorer (ดูตารางความเข้ากันได้ที่นี่ ) สำหรับการแก้ปัญหาข้ามเบราว์เซอร์สำหรับปัญหานี้ฉันจะดูที่FileSaver.js


2

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 และสไตล์เป็นทางเลือกปรับเปลี่ยนสไตล์ตามความต้องการของคุณ


1

ลองตั้งค่าประเภท MIME อื่น: exportData = 'data:application/octet-stream;charset=utf-8,';

แต่อาจมีปัญหากับชื่อไฟล์ในกล่องโต้ตอบบันทึก


ขอโทษที่กลับมาหาคุณช้า ฉันลองคำตอบของคุณแล้วมันดาวน์โหลดไฟล์ แต่มีข้อมูลผิดอยู่ในนั้น .. :(
Eugene Yu

1
สิ่งนี้ใช้งานได้สำหรับฉัน ... data = "data:application/octet-stream;charset=utf-8," + encodeURIComponent(JSON.stringify(data)); window.open(data); มันเพียงดาวน์โหลดไฟล์เป็น "ดาวน์โหลด" แต่ข้อมูลที่ฉันได้รับการทำให้เป็นสตริงแล้วเข้ารหัส uri ตามที่ควรจะเป็น
Jason Wiener

0

หากคุณต้องการตัวอย่างข้อมูล, raser, มากกว่าชื่อไฟล์คุณสามารถทำได้:

window.open(URL.createObjectURL(
    new Blob([JSON.stringify(JSON)], {
      type: 'application/binary'}
    )
))
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.