Tên tệp blob JavaScript không có liên kết


189

Làm thế nào để bạn đặt tên của một tệp blob trong JavaScript khi buộc tải xuống thông qua window.location?

function newFile(data) {
    var json = JSON.stringify(data);
    var blob = new Blob([json], {type: "octet/stream"});
    var url  = window.URL.createObjectURL(blob);
    window.location.assign(url);
}

Chạy đoạn mã trên tải xuống một tệp ngay lập tức mà không cần làm mới trang giống như:

bfefe410-8d9c-4883-86c5-d76c50a24a1d

Thay vào đó, tôi muốn đặt tên tệp là my-download.json .

Câu trả lời:


312

Cách duy nhất tôi biết là thủ thuật được FileSaver.js sử dụng :

  1. Tạo một <a>thẻ ẩn .
  2. Đặt hrefthuộc tính của nó cho URL của blob.
  3. Đặt downloadthuộc tính của nó thành tên tệp.
  4. Bấm vào <a>thẻ.

Dưới đây là một ví dụ đơn giản ( jsfiddle ):

var saveData = (function () {
    var a = document.createElement("a");
    document.body.appendChild(a);
    a.style = "display: none";
    return function (data, fileName) {
        var json = JSON.stringify(data),
            blob = new Blob([json], {type: "octet/stream"}),
            url = window.URL.createObjectURL(blob);
        a.href = url;
        a.download = fileName;
        a.click();
        window.URL.revokeObjectURL(url);
    };
}());

var data = { x: 42, s: "hello, world", d: new Date() },
    fileName = "my-download.json";

saveData(data, fileName);

Tôi đã viết ví dụ này chỉ để minh họa ý tưởng, trong mã sản xuất sử dụng FileSaver.js thay thế.

Ghi chú

  • Các trình duyệt cũ hơn không hỗ trợ thuộc tính "tải xuống", vì đó là một phần của HTML5.
  • Một số định dạng tệp được trình duyệt coi là không an toàn và tải xuống không thành công. Lưu tệp JSON với phần mở rộng txt hoạt động với tôi.

2
@AshBlue Thuộc tính "tải xuống" cần HTML5. Mã của tôi chỉ là một ví dụ, bạn cũng có thể thử trang demo của FileSaver.js
kol

1
Thật thú vị, nếu bạn liên tục cố gắng tải xuống một txt theo cách này (bằng cách nhấn nút Run trên jsfiddle.net nhiều lần), việc tải xuống đôi khi không thành công.
kol

2
Chỉ muốn đề cập rằng giải pháp này sẽ không hoạt động đối với các tệp có kích thước lớn hơn ngưỡng cụ thể. ví dụ:> 2 MB cho chrome. Kích thước này thay đổi từ trình duyệt để trình duyệt.
manojadams

3
Điều này không làm việc cho tôi vì tôi cần mở tệp trong một tab mới. Tôi phải hiển thị PDF trong Chrome, nhưng tôi cần hiển thị tên thân thiện với người dùng trong thanh công cụ URL và nếu người dùng muốn tải xuống thông qua biểu tượng tải xuống, tôi phải đặt cùng tên thân thiện với người dùng trong tệp.
Adrian Paredes

1
Chỉ cần thêm, bạn không cần thực sự gắn thẻ vào phần thân để điều này hoạt động (đã thử ngay trong Chrome)
ngoài mã

52

Tôi chỉ muốn mở rộng câu trả lời được chấp nhận với sự hỗ trợ cho Internet Explorer (hầu hết các phiên bản hiện đại, dù sao) và để dọn dẹp mã bằng jQuery:

$(document).ready(function() {
    saveFile("Example.txt", "data:attachment/text", "Hello, world.");
});

function saveFile (name, type, data) {
    if (data !== null && navigator.msSaveBlob)
        return navigator.msSaveBlob(new Blob([data], { type: type }), name);
    var a = $("<a style='display: none;'/>");
    var url = window.URL.createObjectURL(new Blob([data], {type: type}));
    a.attr("href", url);
    a.attr("download", name);
    $("body").append(a);
    a[0].click();
    window.URL.revokeObjectURL(url);
    a.remove();
}

Dưới đây là một ví dụ Fiddle . Thần tốc .


Làm việc hoàn hảo.
N8allan

1
Tôi đã sử dụng giải pháp được chấp nhận nhưng nó không hoạt động tại firefox! Tôi vẫn không biết tại sao. Giải pháp của bạn đã làm việc trong firefox. Cảm ơn.
elahehab

@elahehab Giải pháp của tôi luôn hoạt động;)
Alexandru

27

Nguyên tắc tương tự như các giải pháp trên. Nhưng tôi gặp vấn đề với Firefox 52.0 (32 bit) trong đó các tệp lớn (> 40 MB) bị cắt ở các vị trí ngẫu nhiên. Lập lịch lại cuộc gọi của revokeObjectUrl () khắc phục sự cố này.

function saveFile(blob, filename) {
  if (window.navigator.msSaveOrOpenBlob) {
    window.navigator.msSaveOrOpenBlob(blob, filename);
  } else {
    const a = document.createElement('a');
    document.body.appendChild(a);
    const url = window.URL.createObjectURL(blob);
    a.href = url;
    a.download = filename;
    a.click();
    setTimeout(() => {
      window.URL.revokeObjectURL(url);
      document.body.removeChild(a);
    }, 0)
  }
}

ví dụ jsfiddle


1
Tôi thấy rằng bản hack setTimeout () này đã sửa lỗi MS Edge, nơi tập tin hoàn toàn không tải xuống. Tuy nhiên, chỉ có lệnh gọi revokeObjectURL () cần bị trì hoãn.
Russell Phillips

Tôi thấy rằng "if (window.navigator.msSaveOrOpenBlob)" là thứ đã tạo ra mánh khóe cho tôi
Jacques Olivier

23

Muộn, nhưng vì tôi gặp vấn đề tương tự, tôi thêm giải pháp của mình:

function newFile(data, fileName) {
    var json = JSON.stringify(data);
    //IE11 support
    if (window.navigator && window.navigator.msSaveOrOpenBlob) {
        let blob = new Blob([json], {type: "application/json"});
        window.navigator.msSaveOrOpenBlob(blob, fileName);
    } else {// other browsers
        let file = new File([json], fileName, {type: "application/json"});
        let exportUrl = URL.createObjectURL(file);
        window.location.assign(exportUrl);
        URL.revokeObjectURL(exportUrl);
    }
}

5
Cảm ơn @ben. Điều này đang làm việc tốt. Không có yếu tố dom, không có gì muốn kích hoạt như sự kiện nhấp chuột. Nó chỉ hoạt động tuyệt vời với phần mở rộng thích hợp. Nhưng tên tệp đã cho không được xem xét, tải xuống "<object_url_id> .csv" thay vì "<myfileName> .csv"
Ram Babu S

3
Gọi revokeObjectURLsau khi location.assignhoạt động tốt trong Firefox, nhưng phá vỡ tải xuống trên Chrome.
Fred

Lưu ý rằng "Edge không hỗ trợ trình tạo tệp." Tham chiếu caniuse.com/#feat=fileapi
user1477388

Đây phải là câu trả lời chính xác. Không có điểm nào trong việc tạo ra các đối tượng vô dụng trong cây DOM
Luiz Felipe

Bây giờ, kể từ ngày 20 tháng 1
Luiz Felipe

6
saveFileOnUserDevice = function(file){ // content: blob, name: string
        if(navigator.msSaveBlob){ // For ie and Edge
            return navigator.msSaveBlob(file.content, file.name);
        }
        else{
            let link = document.createElement('a');
            link.href = window.URL.createObjectURL(file.content);
            link.download = file.name;
            document.body.appendChild(link);
            link.dispatchEvent(new MouseEvent('click', {bubbles: true, cancelable: true, view: window}));
            link.remove();
            window.URL.revokeObjectURL(link.href);
        }
    }

Có cách nào để mở trong đó một cửa sổ mới không?
Enrique Altuna

Tôi nghĩ rằng bạn có thể gọi link.click()thay vì gửi một sự kiện chuột.
Fred

2

Ví dụ hoạt động của nút tải xuống, để lưu ảnh mèo từ url dưới dạng "cat.jpg":

HTML:

<button onclick="downloadUrl('https://i.imgur.com/AD3MbBi.jpg', 'cat.jpg')">Download</button>

JavaScript:

function downloadUrl(url, filename) {
  let xhr = new XMLHttpRequest();
  xhr.open("GET", url, true);
  xhr.responseType = "blob";
  xhr.onload = function(e) {
    if (this.status == 200) {
      const blob = this.response;
      const a = document.createElement("a");
      document.body.appendChild(a);
      const blobUrl = window.URL.createObjectURL(blob);
      a.href = blobUrl;
      a.download = filename;
      a.click();
      setTimeout(() => {
        window.URL.revokeObjectURL(blobUrl);
        document.body.removeChild(a);
      }, 0);
    }
  };
  xhr.send();
}

1

window.location.assign không hoạt động với tôi. nó tải xuống tốt nhưng tải xuống mà không có phần mở rộng cho tệp CSV trên nền tảng Windows. Sau đây làm việc cho tôi.

    var blob = new Blob([csvString], { type: 'text/csv' });
    //window.location.assign(window.URL.createObjectURL(blob));
    var link = window.document.createElement('a');
    link.href = window.URL.createObjectURL(blob);
    // Construct filename dynamically and set to link.download
    link.download = link.href.split('/').pop() + '.' + extension; 
    document.body.appendChild(link);
    link.click();
    document.body.removeChild(link);

0

Đây là giải pháp của tôi. Theo quan điểm của tôi, bạn không thể bỏ qua <a>.

function export2json() {
  const data = {
    a: '111',
    b: '222',
    c: '333'
  };
  const a = document.createElement("a");
  a.href = URL.createObjectURL(
    new Blob([JSON.stringify(data, null, 2)], {
      type: "application/json"
    })
  );
  a.setAttribute("download", "data.json");
  document.body.appendChild(a);
  a.click();
  document.body.removeChild(a);
}
<button onclick="export2json()">Export data to json file</button>

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.