서버에서가 아닌 사용자가 다운로드 할 수 있도록 메모리에 파일을 만드는 방법은 무엇입니까?


824

클라이언트 쪽에서 텍스트 파일을 만들어 서버와 상호 작용하지 않고 다운로드하라는 메시지를 표시 할 수있는 방법이 있습니까? 컴퓨터에 직접 쓸 수는 없지만 (보안 및 모두), 저장하고 작성하라는 메시지를 표시 할 수 있습니까?


답변:


432

데이터 URI를 사용할 수 있습니다. 브라우저 지원은 다양합니다. Wikipedia를 참조하십시오 . 예:

<a href="data:application/octet-stream;charset=utf-16le;base64,//5mAG8AbwAgAGIAYQByAAoA">text file</a>

옥텟 스트림은 다운로드 프롬프트를 강제하는 것입니다. 그렇지 않으면 아마도 브라우저에서 열립니다.

CSV의 경우 다음을 사용할 수 있습니다.

<a href="data:application/octet-stream,field1%2Cfield2%0Afoo%2Cbar%0Agoo%2Cgai%0A">CSV Octet</a>

jsFiddle 데모를 사용해보십시오 .


19
이것은 크로스 브라우저 솔루션이 아니라 볼만한 가치가 있습니다. 예를 들어 IE는 지원을 data uri로 제한합니다. IE 8은 크기를 32KB로 제한하고 IE 7 이하는 전혀 지원하지 않습니다.
Darin Dimitrov

8
Chrome 버전 19.0.1084.46에서이 메소드는 다음과 같은 경고를 생성합니다. "문서로 해석되었지만 MIME 유형 text / csv로 전송 된 자원 :"data : text / csv, field1 % 2Cfield2 % 0Afoo % 2Cbar % 0Agoo % 2Cgai % 0A " " 다운로드가 트리거되지 않음
Chris

2
Chrome에서 작동하지만 (v20 및 v21에서 테스트 됨) IE9는 아닙니다 (jsFiddle 일 수도 있지만 어떻게 든 의심 스럽습니다).
earcam

5
코드를 UTF-8로 변환하지 않는 한 올바른 문자 세트는 거의 UTF-16입니다. JavaScript는 내부적으로 UTF-16을 사용합니다. 텍스트 또는 CSV 파일이있는 경우 UTF-16BE의 바이트 순서 표시 인 '\ ufeff'로 문자열을 시작하면 텍스트 편집기에서 ASCII가 아닌 문자를 올바르게 읽을 수 있습니다.
Larspars

14
적절한 파일 이름과 확장자를 갖기 위해 download = "txt.csv"속성을 추가하고 OS에 처리 방법을 알려주십시오.
elshnkhll 2016 년

724

HTML5 지원 브라우저를위한 간단한 솔루션 ...

function download(filename, text) {
  var element = document.createElement('a');
  element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text));
  element.setAttribute('download', filename);

  element.style.display = 'none';
  document.body.appendChild(element);

  element.click();

  document.body.removeChild(element);
}
form * {
  display: block;
  margin: 10px;
}
<form onsubmit="download(this['name'].value, this['text'].value)">
  <input type="text" name="name" value="test.txt">
  <textarea name="text"></textarea>
  <input type="submit" value="Download">
</form>

용법

download('test.txt', 'Hello world!');

10
네. 이것은 @MatthewFlaschen이 약 3 년 전에 여기에 올린 내용 입니다.
Joseph Silber

48
예, 그러나 download속성을 사용하면 파일 이름을 지정할 수 있습니다 ;-)
Matěj Pokorný

2
@earcam은 이미 위의 의견에서 지적 했듯이 .
Joseph Silber

4
txt파일 이름에 확장자를 제공하지 않으면 Chrome은 확장자 만 추가합니다 . 그렇게 download("data.json", data)하면 예상대로 작동합니다.
Carl Smith

6
이것은 Chrome (73.0.3683.86) 및 Firefox (66.0.2)에서 저에게 효과적이었습니다. 그것은 않았다 하지 IE11 (11.379.17763.0) 및 에지 (44.17763.1.0)에서 작동합니다.
Sam

231

위의 모든 솔루션이 모든 브라우저에서 작동하지는 않았습니다. 여기에 마지막으로 (그리고 IE 10 +, 파이어 폭스와 크롬에서 작동 무엇 없이 jQuery를 또는 다른 라이브러리) :

save: function(filename, data) {
    var blob = new Blob([data], {type: 'text/csv'});
    if(window.navigator.msSaveOrOpenBlob) {
        window.navigator.msSaveBlob(blob, filename);
    }
    else{
        var elem = window.document.createElement('a');
        elem.href = window.URL.createObjectURL(blob);
        elem.download = filename;        
        document.body.appendChild(elem);
        elem.click();        
        document.body.removeChild(elem);
    }
}

상황에 따라를 제거한 후 URL.revokeObjectURL 을 호출 할 수도 있습니다 elem. URL.createObjectURL 에 대한 문서에 따르면 :

createObjectURL ()을 호출 할 때마다 동일한 객체에 대해 이미 생성 한 경우에도 새 객체 URL이 생성됩니다. 더 이상 필요하지 않은 경우 URL.revokeObjectURL ()을 호출하여 각 릴리스를 해제해야합니다. 브라우저는 문서가 언로드 될 때 자동으로이를 해제합니다. 그러나 최적의 성능과 메모리 사용을 위해 명시 적으로 언로드 할 수있는 안전한 시간이 있으면 그렇게해야합니다.


7
정말 고마워. 나는 여기에 나열된 모든 예제를 시도했지만이 브라우저에서만 작동합니다. 이것이 정답입니다.
LEM

Chrome에서는 실제로 이것을 작동시키기 위해 요소를 본문에 추가 할 필요가 없었습니다.
JackMorrissey

1
AngularJS 1.x 앱의 경우 Urls가 생성 될 때 배열을 구성한 다음 구성 요소의 $ onDestroy 함수에서 정리할 수 있습니다. 이것은 나를 위해 잘 작동합니다.
Splaktar

1
다른 답변은 Failed: network errorChrome으로 이어졌습니다 . 이것은 잘 작동합니다.
juniper-

4
이것은 Chrome (73.0.3683.86), Firefox (66.0.2), IE11 (11.379.17763.0) 및 Edge (44.17763.1.0)에서 저에게 효과적이었습니다.
Sam

185

위의 모든 예제는 크롬과 IE에서 잘 작동하지만 Firefox에서는 실패합니다. 본체에 앵커를 추가하고 클릭 후 제거하는 것을 고려하십시오.

var a = window.document.createElement('a');
a.href = window.URL.createObjectURL(new Blob(['Test,Text'], {type: 'text/csv'}));
a.download = 'test.csv';

// Append anchor to body.
document.body.appendChild(a);
a.click();

// Remove anchor from body
document.body.removeChild(a);

4
그러나 IE 10a.click() 에는 블롭 URL이 교차 출처라고 생각하기 때문에 "액세스가 거부되었습니다"라는 오류가 발생하는 IE 10에는 오픈 버그가 있습니다 .
Matt

@Matt data uri는 일부 브라우저에서 교차 출처입니다. 내가 아는 한 msie뿐만 아니라 크롬에서도. data uri로 자바 스크립트를 주입하여 테스트 할 수 있습니다. 그것은 사이트의 다른 부분에 액세스 할 수 없습니다 ...
inf3rno

7
"위의 모든 예제는 크롬과 IE에서 잘 작동하지만 Firefox에서는 실패합니다." 답변 순서는 시간이 지남에 따라 변경 될 수 있으므로,이 답변을 작성할 때 어떤 답변이 귀하의 답변 위에 있는지는 확실하지 않습니다. Firefox에서 작동하지 않는 방법을 정확하게 나타낼 수 있습니까?
Kevin

120

FileSaver.js를 행복하게 사용하고 있습니다. 호환성이 뛰어나고 (IE10 + 및 그 밖의 모든 것), 사용하기 매우 간단합니다 :

var blob = new Blob(["some text"], {
    type: "text/plain;charset=utf-8;",
});
saveAs(blob, "thing.txt");

이것은 Chrome에서 훌륭하게 작동합니다. 사용자가 디스크에서 파일의 위치를 ​​지정하도록하려면 어떻게해야합니까?
gregm

6
사용하기 쉬운 라이브러리 덕분입니다. 이것은 가장 좋은 대답이며 누가 요즘 HTML <5를 사용하는 사람들을 걱정합니까?
notbad.jpeg

@gregm이 플러그인으로 확실하지 않습니다.
Daniel Buckmaster

@gregm : 다운로드 위치를 의미합니까? FileSaver.js와 관련이 없으므로 다운로드 할 때마다 폴더를 요청하거나에 새로운 다운로드 속성 을 사용하도록 브라우저 구성을 설정해야합니다 <a>.
CodeManX

1
이것은 IE 10+ 브라우저 제품군에 적합한 솔루션입니다. IE는 아직 다운로드 HTML 5 태그를 지원하지 않으며이 페이지의 다른 솔루션 (및 동일한 문제를 논의하는 다른 SO 페이지)은 단순히 작동하지 않았습니다. FileSaver ftw!
TMc

22

다음 방법은 IE11 +, Firefox 25+ 및 Chrome 30+에서 작동합니다.

<a id="export" class="myButton" download="" href="#">export</a>
<script>
    function createDownloadLink(anchorSelector, str, fileName){
        if(window.navigator.msSaveOrOpenBlob) {
            var fileData = [str];
            blobObject = new Blob(fileData);
            $(anchorSelector).click(function(){
                window.navigator.msSaveOrOpenBlob(blobObject, fileName);
            });
        } else {
            var url = "data:text/plain;charset=utf-8," + encodeURIComponent(str);
            $(anchorSelector).attr("download", fileName);               
            $(anchorSelector).attr("href", url);
        }
    }

    $(function () {
        var str = "hi,file";
        createDownloadLink("#export",str,"file.txt");
    });

</script>

동작에서 이것을보십시오 : http://jsfiddle.net/Kg7eA/

Firefox 및 Chrome은 탐색을 위해 데이터 URI를 지원하므로 데이터 URI로 이동하여 파일을 만들 수 있지만 IE는 보안 목적으로 파일 URI를 지원하지 않습니다.

반면, IE에는 Blob을 저장하기위한 API가 있으며 파일을 만들고 다운로드하는 데 사용할 수 있습니다.


방금 jquery를 사용하여 이벤트 (onclick 및 onready)를 첨부하고 속성을 설정했습니다.이 속성은 바닐라 JS로도 가능합니다. 핵심 부분 (window.navigator.msSaveOrOpenBlob)에는 jquery가 필요하지 않습니다.
dinesh ygv 2

데이터 URI 접근 방식의 크기에는 여전히 제한이 있습니까?
phil

msSaveOrOpenBlob은 더 이상 사용되지 않는 것으로 표시됩니다. developer.mozilla.org/en-US/docs/Web/API/Navigator/msSaveBlob
eflat

13

이 솔루션은 tiddlywiki (tiddlywiki.com) github 저장소에서 직접 추출됩니다. 거의 모든 브라우저에서 tiddlywiki를 사용했으며 매력처럼 작동합니다.

function(filename,text){
    // Set up the link
    var link = document.createElement("a");
    link.setAttribute("target","_blank");
    if(Blob !== undefined) {
        var blob = new Blob([text], {type: "text/plain"});
        link.setAttribute("href", URL.createObjectURL(blob));
    } else {
        link.setAttribute("href","data:text/plain," + encodeURIComponent(text));
    }
    link.setAttribute("download",filename);
    document.body.appendChild(link);
    link.click();
    document.body.removeChild(link);
}

Github Repo : 다운로드 세이버 모듈


Chrome에서는 잘 작동하지만 Firefox에서는 잘 작동하지 않습니다. 파일을 만들어 다운로드하지만 파일이 비어 있습니다. 콘텐츠 없음. 어떤 아이디어가 있습니까? IE에서 테스트하지 않았습니다 ...
Narxx

2
함수에 이름이 없다는 것을 제외하고는 이것이 내가 가장 좋아하는 것입니다.
Yoraco Gonzales

11

IE10에서 작동하는 솔루션 : (CSV 파일이 필요했지만 유형과 파일 이름을 txt로 변경하면 충분합니다)

var csvContent=data; //here we load our csv data 
var blob = new Blob([csvContent],{
    type: "text/csv;charset=utf-8;"
});

navigator.msSaveBlob(blob, "filename.csv")

1
Ludovic의 답변 에는이 큰 브라우저와 다른 브라우저에 대한 지원이 포함됩니다.
Dan Dascalescu


10

패키지 의 js 파일 다운로드 에서 github.com/kennethjiang/js-file-download의 브라우저 지원에 대한 핸들 에지의 경우 :

소스보기이 페이지에서 언급 된 기술을 사용하는 방법을 보려면 를보십시오.

설치

yarn add js-file-download
npm install --save js-file-download

용법

import fileDownload from 'js-file-download'

// fileDownload(data, filename, mime)
// mime is optional

fileDownload(data, 'filename.csv', 'text/csv')

1
고마워-방금 테스트-Windows의 Firefox, Chrome 및 Edge에서 작동
Brian Burns

8

앞에서 언급했듯이 filesaver 는 클라이언트 쪽에서 파일을 처리하기위한 훌륭한 패키지입니다. 그러나 큰 파일에는 적합하지 않습니다. StreamSaver.js 는 큰 파일을 처리 할 수있는 대체 솔루션입니다 (FileServer.js에 있음).

const fileStream = streamSaver.createWriteStream('filename.txt', size);
const writer = fileStream.getWriter();
for(var i = 0; i < 100; i++){
    var uint8array = new TextEncoder("utf-8").encode("Plain Text");
    writer.write(uint8array);
}
writer.close()

1
Text Encoder는 현재 매우 실험적이므로 피하지 않는 것이 좋습니다.
Brandon.Blanchard

7
var element = document.createElement('a');
element.setAttribute('href', 'data:text/text;charset=utf-8,' +      encodeURI(data));
element.setAttribute('download', "fileName.txt");
element.click();

1
이 방법과 Blob 생성의 차이점은 무엇입니까?
Dan Dascalescu


5

@Rick 답변을 바탕으로 정말 도움이되었습니다.

data이 방법으로 공유 하려면 문자열을 이스케이프 해야합니다.

$('a.download').attr('href', 'data:application/csv;charset=utf-8,'+ encodeURI(data));

`죄송합니다. 현재 StackOverflow에서 명성이 낮기 때문에 @Rick의 답변에 대해 언급 할 수 없습니다.

편집 제안은 공유 거부되었습니다.


1
나는 제안을 받아 들일 수 없었다. 이상한 ... 코드를 업데이트했습니다.
Rick

4

URL API, 특히 URL.createObjectURL ()Blob을 사용할 수 있습니다. API를 인코딩 및 다운로드 거의 아무것도.

다운로드가 작은 경우 다음과 같이 작동합니다.

document.body.innerHTML += 
`<a id="download" download="PATTERN.json" href="${URL.createObjectURL(new Blob([JSON.stringify("HELLO WORLD", null, 2)]))}"> Click me</a>`
download.click()
download.outerHTML = ""


DOM을 사용하는 대신 다운로드가 크면 다운로드 매개 변수로 링크 요소를 작성하고 클릭을 트리거하는 것이 더 좋습니다.

링크 요소는 문서에 추가되지 않지만 클릭은 작동합니다. 이 방법으로 수백 개의 Mo를 다운로드 할 수 있습니다.

const stack = {
 some: "stuffs",
 alot: "of them!"
}

BUTTONDOWNLOAD.onclick = (function(){
  let j = document.createElement("a")
  j.id = "download"
  j.download = "stack_"+Date.now()+".json"
  j.href = URL.createObjectURL(new Blob([JSON.stringify(stack, null, 2)]))
  j.click()
})  
<button id="BUTTONDOWNLOAD">DOWNLOAD!</button>


보너스! 순환 객체를 다운로드 하고 오류를 피하십시오.

TypeError : 순환 객체 값 (Firefox) TypeError : 변환 중

JSON에 대한 순환 구조 (Chrome 및 Opera) TypeError : Circular

값 인수에서 참조가 지원되지 않음 (에지)

https://github.com/douglascrockford/JSON-js/blob/master/cycle.js 사용

이 예에서는 document객체를 json으로 다운로드합니다 .

/* JSON.decycle */
if(typeof JSON.decycle!=="function"){JSON.decycle=function decycle(object,replacer){"use strict";var objects=new WeakMap();return(function derez(value,path){var old_path;var nu;if(replacer!==undefined){value=replacer(value)}
if(typeof value==="object"&&value!==null&&!(value instanceof Boolean)&&!(value instanceof Date)&&!(value instanceof Number)&&!(value instanceof RegExp)&&!(value instanceof String)){old_path=objects.get(value);if(old_path!==undefined){return{$ref:old_path}}
objects.set(value,path);if(Array.isArray(value)){nu=[];value.forEach(function(element,i){nu[i]=derez(element,path+"["+i+"]")})}else{nu={};Object.keys(value).forEach(function(name){nu[name]=derez(value[name],path+"["+JSON.stringify(name)+"]")})}
return nu}
return value}(object,"$"))}}


document.body.innerHTML += 
`<a id="download" download="PATTERN.json" href="${URL.createObjectURL(new Blob([JSON.stringify(JSON.decycle(document), null, 2)]))}"></a>`
download.click()



2

아래 기능이 작동했습니다.

 private createDownloadableCsvFile(fileName, content) {
   let link = document.createElement("a");
   link.download = fileName;
   link.href = `data:application/octet-stream,${content}`;
   return link;
 }

fileName을 할당 된 상태로 유지하면서 다운로드하지 않고 새 탭에서 파일을 열 수 있습니까?
Carl Kroeger Ihl

1

다음 방법은 IE10 +, Edge, Opera, FF 및 Chrome에서 작동합니다.

const saveDownloadedData = (fileName, data) => {
    if(~navigator.userAgent.indexOf('MSIE') || ~navigator.appVersion.indexOf('Trident/')) { /* IE9-11 */
        const blob = new Blob([data], { type: 'text/csv;charset=utf-8;' });
        navigator.msSaveBlob(blob, fileName);
    } else {
        const link = document.createElement('a')
        link.setAttribute('target', '_blank');
        if(Blob !== undefined) {
            const blob = new Blob([data], { type: 'text/plain' });
            link.setAttribute('href', URL.createObjectURL(blob));
        } else {
            link.setAttribute('href', 'data:text/plain,' + encodeURIComponent(data));
        }

        ~window.navigator.userAgent.indexOf('Edge')
            && (fileName = fileName.replace(/[&\/\\#,+$~%.'':*?<>{}]/g, '_')); /* Edge */

        link.setAttribute('download', fileName);
        document.body.appendChild(link);
        link.click();
        document.body.removeChild(link);
    }
}

따라서 함수를 호출하십시오.

saveDownloadedData('test.txt', 'Lorem ipsum');

0

나에게 이것은 동일한 파일 이름과 확장명이 다운로드되어 완벽하게 작동했습니다.

<a href={"data:application/octet-stream;charset=utf-16le;base64," + file64 } download={title} >{title}</a>

'제목'확장 예와 파일 이름입니다, sample.pdf, waterfall.jpg, 등

'file64'는 이와 같은 base64 콘텐츠입니다. Ww6IDEwNDAsIFNsaWRpbmdTY2FsZUdyb3VwOiAiR3JvdXAgQiIsIE1lZGljYWxWaXNpdEZsYXRGZWU6IDM1LCBEZW50YWxQYXltZW50UGVyY2VudGFnZTogMjUsIFByb2NlZHVyZVBlcmNlbnQ6IDcwLKCFfSB7IkdyYW5kVG90YWwiOjEwNDAsIlNsaWRpbmdTY2FsZUdyb3VwIjoiR3JvdXAgQiIsIk1lZGljYWxWaXNpdEZsYXRGZWUiOjM1LCJEZW50YWxQYXltZW50UGVyY2VudGFnZSI6MjUsIlByb2NlZHVyZVBlcmNlbnQiOjcwLCJDcmVhdGVkX0J5IjoiVGVycnkgTGVlIiwiUGF0aWVudExpc3QiOlt7IlBhdGllbnRO


0

<a></a>태그를 사용한 다음을 설정합니다 href='path'. 그런 다음 이미지를 <a>시각적으로 볼 수 있도록 요소 사이에 이미지를 배치 하십시오. 원하는 경우 href동일한 링크가 아니라 동적 이 되도록 변경하는 함수를 작성할 수 있습니다 .

자바 스크립트로 액세스 하려면 <a>태그에 태그를 지정하십시오 id.

HTML 버전으로 시작 :

<a href="mp3/tupac_shakur-how-do-you-want-it.mp3" download id="mp3Anchor">
     <img src="some image that you want" alt="some description" width="100px" height="100px" />
</a>

이제 JavaScript로 :

*Create a small json file*;

const array = [
     "mp3/tupac_shakur-how-do-you-want-it.mp3",
     "mp3/spice_one-born-to-die.mp3",
     "mp3/captain_planet_theme_song.mp3",
     "mp3/tenchu-intro.mp3",
     "mp3/resident_evil_nemesis-intro-theme.mp3"
];

//load this function on window
window.addEventListener("load", downloadList);

//now create a function that will change the content of the href with every click
function downloadList() {
     var changeHref=document.getElementById("mp3Anchor");

     var j = -1;

     changeHref.addEventListener("click", ()=> {

           if(j < array.length-1) {
               j +=1;
               changeHref.href=""+array[j];
          }
           else {
               alert("No more content to download");
          }
}

-22

파일에 텍스트 데이터가 포함 된 경우, 내가 사용하는 기술은 텍스트를 텍스트 영역 요소에 넣고 사용자가 텍스트 영역을 클릭하고 (textarea를 클릭 한 다음 ctrl-A) 텍스트 편집기에 붙여 넣기를 수행하도록하는 것입니다.


30
나는 그것을 고려했지만 사용자 친화적 인 관점에서 이것은 비참합니다. 또한 파일은 CSV 확장자로 저장해야합니다. 사용자에게 알려주십시오.
Joseph Silber
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.