링크가없는 JavaScript Blob 파일 이름


189

window.location을 통해 강제로 다운로드 할 때 JavaScript에서 Blob 파일의 이름을 어떻게 설정합니까?

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

위 코드를 실행하면 다음과 같은 페이지 새로 고침없이 파일이 즉시 다운로드됩니다.

bfefe410-8d9c-4883-86c5-d76c50a24a1d

대신 파일 이름을 my-download.json 으로 설정하고 싶습니다 .

답변:


312

내가 아는 유일한 방법은 FileSaver.js가 사용하는 트릭입니다 .

  1. 숨겨진 <a>태그를 만듭니다 .
  2. 해당 href속성을 Blob의 URL로 설정하십시오 .
  3. download속성을 파일 이름으로 설정하십시오 .
  4. <a>태그를 클릭하십시오 .

다음은 간단한 예입니다 ( 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);

아이디어를 설명하기 위해이 예제를 작성했습니다. 프로덕션 코드에서는 FileSaver.js를 대신 사용하십시오.

노트

  • 이전 브라우저는 HTML5의 일부이므로 "다운로드"속성을 지원하지 않습니다.
  • 일부 파일 형식은 브라우저에서 안전하지 않은 것으로 간주되어 다운로드가 실패합니다. txt 확장자로 JSON 파일을 저장하면 효과적입니다.

2
@AshBlue "download"속성에는 HTML5가 필요합니다. 내 코드는 예일 뿐이며
kol

1
흥미롭게도, jsfiddle.net의 실행 버튼을 반복해서 반복해서 이런 식으로 txt를 반복해서 다운로드하려고하면 다운로드가 실패하는 경우가 있습니다.
kol

2
이 솔루션은 특정 임계 값보다 큰 크기의 파일에는 작동하지 않습니다. 예를 들어-크롬의 경우 2MB입니다. 이 크기는 브라우저마다 다릅니다.
manojadams

3
새 탭에서 파일을 열어야하기 때문에이 기능이 작동하지 않습니다. Chrome에서 PDF를 표시해야하지만 URL 툴바에 사용자에게 친숙한 이름을 표시해야하며, 사용자가 다운로드 아이콘을 통해 다운로드하려면 파일에 동일한 사용자에게 친숙한 이름을 넣어야합니다.
Adrian Paredes

1
추가하기 만하면 실제로 태그를 본문에 마운트 할 필요가 없습니다 (지금 Chrome에서 시도)
이상 - 코드

52

Internet Explorer (대부분 최신 버전)를 지원하여 허용되는 답변을 확장하고 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();
}

여기 Fiddle의 예가 있습니다. Godspeed .


완벽하게 작동했습니다.
N8allan

1
허용 된 솔루션을 사용했지만 파이어 폭스에서 작동하지 않았습니다! 나는 아직도 이유를 모른다. 귀하의 솔루션은 파이어 폭스에서 작동했습니다. 감사.
elahehab

@elahehab 내 솔루션은 항상 작동합니다.)
Alexandru

27

위의 솔루션과 동일한 원칙. 그러나 큰 파일 (> 40MB)이 임의 위치에서 잘리는 Firefox 52.0 (32 비트)에 문제가있었습니다. revokeObjectUrl () 호출을 다시 예약하면이 문제가 해결됩니다.

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

jsfiddle 예제


1
이 setTimeout () 해킹은 파일이 전혀 다운로드되지 않는 MS Edge를 수정한다는 것을 알았습니다. 그러나 revokeObjectURL () 호출 만 지연되어야합니다.
Russell Phillips

나는이 "(window.navigator.msSaveOrOpenBlob)가"나를 위해 속임수를 썼는지 어떤 것을 발견
자크 올리비에

23

늦었지만 같은 문제가 있었으므로 솔루션을 추가했습니다.

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
감사합니다 @ben. 이것은 잘 작동합니다. dom 요소가 없으며 클릭 이벤트처럼 트리거하는 것이 없습니다. 적절한 확장으로 훌륭하게 작동합니다. 그러나 주어진 파일 이름은 "<myfileName> .csv"대신 "<object_url_id> .csv"를 다운로드하는 것으로 간주되지 않습니다.
Ram Babu S

3
revokeObjectURL이후에 호출 location.assign하면 Firefox에서 제대로 작동하지만 Chrome에서 다운로드가 중단됩니다.
Fred

"Edge는 File 생성자를 지원하지 않습니다." 참조 caniuse.com/#feat=fileapi
user1477388

이것이 정답이어야합니다. DOM 트리에서 쓸모없는 객체를 만들 필요가 없음
Luiz Felipe

1 월 20 일 이후
루이즈 펠리페

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

새 창을 열 수있는 방법이 있습니까?
Enrique Altuna

link.click()마우스 이벤트를 전달하는 대신 전화 를 걸 수 있다고 생각합니다 .
Fred

2

작업 예 "cat.jpg"와 같은 URL에서 고양이 사진을 저장, 다운로드 버튼의 :

HTML :

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

자바 스크립트 :

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이 작동하지 않았습니다. 그것은 잘 다운로드하지만 Windows 플랫폼에서 CSV 파일의 확장자가없는 다운로드. 다음은 나를 위해 일했습니다.

    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

이것이 나의 해결책이다. 내 관점에서는을 (를) 우회 할 수 없습니다 <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>

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.