Tải xuống đối tượng JSON dưới dạng tệp từ trình duyệt


143

Tôi có đoạn mã sau để cho phép người dùng tải xuống chuỗi dữ liệu trong tệp csv.

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

Nó hoạt động tốt nếu khách hàng chạy mã, nó tạo trang trống và bắt đầu tải xuống dữ liệu trong tệp csv.

Vì vậy, tôi đã cố gắng làm điều này với đối tượng JSON như

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

Nhưng tôi chỉ thấy một trang có dữ liệu JSON được hiển thị trên đó, không tải xuống.

Tôi đã trải qua một số nghiên cứu và điều này khẳng định sẽ hoạt động nhưng tôi không thấy bất kỳ sự khác biệt nào đối với mã của tôi.

Tôi có thiếu một cái gì đó trong mã của tôi?

Cảm ơn đã đọc câu hỏi của tôi :)

Câu trả lời:


255

Đây là cách tôi giải quyết nó cho ứng dụng của mình:

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

JS (JS thuần túy, không phải jQuery ở đây):

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

Trong trường hợp này, storageObjlà đối tượng js bạn muốn lưu trữ và "cảnh.json" chỉ là tên ví dụ cho tệp kết quả.

Cách tiếp cận này có những ưu điểm sau so với các đề xuất khác:

  • Không cần phải nhấp vào phần tử HTML nào
  • Kết quả sẽ được đặt tên như bạn muốn
  • không cần jQuery

Tôi cần hành vi này mà không cần nhấp chuột rõ ràng vì tôi muốn kích hoạt tải xuống tự động tại một số điểm từ js.

Giải pháp JS (không yêu cầu 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
Đây là giải pháp duy nhất sẽ hoạt động với hơn = ~ 2000 ký tự dữ liệu. Bởi vì bạn đã chuẩn bị dữ liệu:
rjurney

1
Ai đó có thể chỉ cho tôi một trang đặc tả hoặc MDN giải thích chi tiết hơn về cách thức toàn bộ điều loại dữ liệu được chuẩn bị này hoạt động không. "dữ liệu: văn bản / json; charset = utf-8"? Tôi đang sử dụng cái này, nhưng nó có cảm giác như ma thuật, sẽ rất tuyệt khi đọc chi tiết nhưng tôi thậm chí không biết làm thế nào để google cho nó.
sidinderguy

1
Điều này không hoạt động trong IE mặc dù khi bạn phải tải xuống một tệp lớn với hơn 2000 ký tự.
dùng388969

12
Điều này sẽ không làm việc mà không có giới hạn, mặc dù. Bạn chỉ có thể tải xuống khoảng 1 MB dữ liệu. Ví dụ: var storageObj = []; for (var i=0; i<1000000; ++i) storageObj.push('aaa');cung cấp "tải xuống thất bại - Lỗi mạng" trong Chrome 61
oseiskar

1
@YASHDAVE sử dụng JSON.stringify(exportObj, null, 2)thay thế
TryingToImprove

40

Tìm thấy một câu trả lời.

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

dường như làm việc tốt cho tôi

** Tất cả tín dụng thuộc về @ cowboy-ben-alman, tác giả của đoạn mã trên **


@Cybear bạn có thể giải thích dòng thứ ba cho tôi?
Rahul Khatri

Bạn sẽ muốn thêm dữ liệu: vào url của mình, nếu không, người dùng có thể đạt giới hạn 2000 ký tự trong nhiều trình duyệt.
rjurney

Xin chào, tôi biết đó là một câu trả lời cũ nhưng, biết rằng giải pháp này không hoạt động trên IE (tất cả chúng) IE không quen thuộc với tham chiếu thuộc tính tải xuống - liên kết
Ayalon Grinfeld

25

Đây sẽ là phiên bản thuần túy (được chuyển thể từ cao bồi):

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
Cảm ơn câu trả lời ngay cả sau khi đã được 2 năm kể từ khi tôi hỏi câu hỏi này! Tôi thích JS thuần hơn cú pháp jQuery.
Eugene Yu

Bạn sẽ muốn thêm dữ liệu: vào url của mình, nếu không, người dùng có thể đạt giới hạn 2000 ký tự trong nhiều trình duyệt.
rjurney

Làm thế nào tôi có thể làm cho tải xuống này bắt đầu tải trang. Bất cứ khi nào người dùng duyệt url trang, anh ta sẽ được nhắc tải xuống
user388969

1
Bài kiểm tra hôm nay trong Edge: data.json không thể tải xuống.
Sarah Tree

24

Bạn có thể thử sử dụng:

Không cần phải đối phó với bất kỳ yếu tố HTML nào cả.

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

Nếu bạn muốn in JSON đẹp, theo câu trả lời này , bạn có thể sử dụng:

JSON.stringify(data,undefined,2)

1
saveAs () là từ FileSaver.js - github.com/eligrey/FileSaver.js
Gautham

1
"Không cần phải đối phó với bất kỳ yếu tố HTML nào" ... và đọc mã nguồn của filesaver.js ... nó thực sự chính xác như vậy
Cuộc chiến

1
Vâng. Tôi muốn nói, không cần phải xử lý trực tiếp các yếu tố HTML.
Gautham

3
Đây là câu trả lời tốt nhất vì nó không có giới hạn kích thước 1MB và sử dụng thư viện thay vì hack tùy chỉnh
oseiskar

đã bình chọn cho tham chiếu FileSaver. làm việc hoàn hảo
Không có ai

15

Sau đây làm việc cho tôi:

/* 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)
}

và sau đó gọi nó như vậy

saveJSON(myJsonObject, "saved_data.json");

3
Mặc dù đây là một câu trả lời tuyệt vời, initMouseEvent()là một Tiêu chuẩn Web không dùng nữa và không nên được sử dụng nữa. Thay vào đó, hãy sử dụng new MouseEvent()giao diện. Nó chỉ là một cấu trúc lại nhỏ.
morkro

10

Gần đây tôi đã phải tạo một nút có thể tải xuống một tệp json của tất cả các giá trị của một hình thức lớn. Tôi cần điều này để làm việc với IE / Edge / Chrome. Đây là những gì tôi đã làm:

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

Có một vấn đề với tên tệp và phần mở rộng ở cạnh nhưng tại thời điểm viết bài này dường như là một lỗi với Edge đã được sửa.

Hy vọng điều này sẽ giúp ai đó


Điều này hoạt động trên Chrome, nhưng dường như không hoạt động trên Firefox ... vui lòng trợ giúp! codepen.io/anon/pen/ePYPJb
Urmil Parikh

1
Chức năng tuyệt vời, thêm document.body.appendChild(a); a.style.display = 'none';để làm cho nó hoạt động trong Firefox.
Fabian von Ellerts

5

Giải pháp đơn giản, gọn gàng cho những người chỉ nhắm mục tiêu các trình duyệt hiện đại:

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

Cảm ơn, chỉ có một vấn đề không gây ra cho tôi vấn đề kích thước
Roelant

4

Các downloadtài sản của liên kết là mới và không được hỗ trợ trong Internet Explorer (xem bảng tính tương thích ở đây ). Đối với một giải pháp trình duyệt chéo cho vấn đề này, tôi sẽ xem FileSaver.js


2

React : thêm cái này vào nơi bạn muốn trong phương thức render của bạn.

• Đối tượng ở trạng thái :

<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>

• Đối tượng trong đạo cụ :

<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 và style là tùy chọn, sửa đổi kiểu theo nhu cầu của bạn.


1

Hãy thử đặt loại MIME khác: exportData = 'data:application/octet-stream;charset=utf-8,';

Nhưng có thể có vấn đề với tên tệp trong hộp thoại lưu.


Xin lỗi vì đã quay lại với bạn muộn. Tôi đã thử câu trả lời của bạn và nó không tải xuống tệp nhưng chứa dữ liệu sai trong đó .. :(
Eugene Yu

1
điều này làm việc cho tôi ... data = "data:application/octet-stream;charset=utf-8," + encodeURIComponent(JSON.stringify(data)); window.open(data); nó chỉ đơn giản là tải xuống tệp dưới dạng "tải xuống" nhưng dữ liệu tôi được xâu chuỗi và sau đó được mã hóa bằng uri.
Jason Wiener

0

Nếu bạn thích đoạn mã điều khiển, raser, hơn tên tệp, bạn có thể làm điều này:

window.open(URL.createObjectURL(
    new Blob([JSON.stringify(JSON)], {
      type: 'application/binary'}
    )
))
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.