มีวิธีใดบ้างที่ฉันสามารถสร้างไฟล์ข้อความทางฝั่งไคลเอ็นต์และแจ้งให้ผู้ใช้ดาวน์โหลดโดยไม่ต้องมีการโต้ตอบกับเซิร์ฟเวอร์ ฉันรู้ว่าฉันไม่สามารถเขียนโดยตรงไปยังเครื่องของพวกเขา (ความปลอดภัยและทั้งหมด) แต่ฉันสามารถสร้างและแจ้งให้พวกเขาบันทึกได้หรือไม่
มีวิธีใดบ้างที่ฉันสามารถสร้างไฟล์ข้อความทางฝั่งไคลเอ็นต์และแจ้งให้ผู้ใช้ดาวน์โหลดโดยไม่ต้องมีการโต้ตอบกับเซิร์ฟเวอร์ ฉันรู้ว่าฉันไม่สามารถเขียนโดยตรงไปยังเครื่องของพวกเขา (ความปลอดภัยและทั้งหมด) แต่ฉันสามารถสร้างและแจ้งให้พวกเขาบันทึกได้หรือไม่
คำตอบ:
คุณสามารถใช้ URI ข้อมูล การสนับสนุนเบราว์เซอร์แตกต่างกันไป ดูวิกิพีเดีย ตัวอย่าง:
<a href="data:application/octet-stream;charset=utf-16le;base64,//5mAG8AbwAgAGIAYQByAAoA">text file</a>
octet-stream คือการบังคับให้พรอมต์ดาวน์โหลด มิฉะนั้นจะเปิดในเบราว์เซอร์
สำหรับ CSV คุณสามารถใช้:
<a href="data:application/octet-stream,field1%2Cfield2%0Afoo%2Cbar%0Agoo%2Cgai%0A">CSV Octet</a>
ลองสาธิต jsFiddle
ทางออกที่ง่ายสำหรับเบราว์เซอร์ที่พร้อมใช้ 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!');
download
แอตทริบิวต์คุณสามารถระบุชื่อไฟล์ ;-)
txt
ส่วนขยายเฉพาะในกรณีที่คุณไม่ได้ให้ส่วนขยายในชื่อไฟล์ ถ้าคุณทำdownload("data.json", data)
มันจะทำงานตามที่คาดไว้
โซลูชันด้านบนทั้งหมดไม่สามารถใช้ได้กับเบราว์เซอร์ทั้งหมด นี่คือสิ่งที่ใช้งานได้ใน IE 10+, Firefox และ Chrome (และไม่มี 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.revokeObjectURLelem
หลังจากลบ ตามเอกสารสำหรับURL.createObjectURL :
ทุกครั้งที่คุณเรียก createObjectURL () จะมีการสร้าง URL วัตถุใหม่แม้ว่าคุณจะสร้างไว้สำหรับวัตถุเดียวกันแล้วก็ตาม แต่ละรายการเหล่านี้ต้องได้รับการปล่อยตัวโดยการเรียก URL.revokeObjectURL () เมื่อคุณไม่ต้องการใช้อีกต่อไป เบราว์เซอร์จะปล่อยสิ่งเหล่านี้โดยอัตโนมัติเมื่อไม่มีการโหลดเอกสาร อย่างไรก็ตามเพื่อประสิทธิภาพที่ดีที่สุดและการใช้หน่วยความจำหากมีเวลาที่ปลอดภัยเมื่อคุณสามารถยกเลิกการโหลดได้อย่างชัดเจนคุณควรทำเช่นนั้น
Failed: network error
ใน Chrome อันนี้ใช้ได้ดี
ตัวอย่างข้างต้นทั้งหมดทำงานได้ดีใน chrome และ 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);
a.click()
บรรทัดเพราะคิดว่า URL หยดเป็นข้ามแหล่งกำเนิด
ฉันมีความสุขโดยใช้FileSaver.js ความเข้ากันได้ค่อนข้างดี (IE10 + และทุกอย่างอื่น) และใช้งานง่ายมาก:
var blob = new Blob(["some text"], {
type: "text/plain;charset=utf-8;",
});
saveAs(blob, "thing.txt");
<a>
บน
วิธีการต่อไปนี้ใช้งานได้ใน 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 สำหรับการนำทางซึ่งช่วยให้เราสามารถสร้างไฟล์โดยไปที่ data URI ในขณะที่ IE ไม่รองรับเพื่อความปลอดภัย
ในทางตรงกันข้าม IE มี API สำหรับการบันทึกหยดซึ่งสามารถใช้ในการสร้างและดาวน์โหลดไฟล์
โซลูชันนี้ถูกดึงโดยตรงจากที่เก็บ github ของ tiddlywiki (tiddlywiki.com) ฉันใช้ 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: ดาวน์โหลดโมดูลตัวรักษาความปลอดภัย
โซลูชันที่ทำงานบน 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")
หากคุณต้องการแปลงสตริงให้พร้อมสำหรับการดาวน์โหลดคุณสามารถลองใช้ jQuery
$('a.download').attr('href', 'data:application/csv;charset=utf-8,' + encodeURI(data));
แพ็คเกจjs-file-downloadจาก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')
ดังที่ได้กล่าวมาแล้ว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()
var element = document.createElement('a');
element.setAttribute('href', 'data:text/text;charset=utf-8,' + encodeURI(data));
element.setAttribute('download', "fileName.txt");
element.click();
ตั้งแต่เดือนเมษายน 2014, FileSytem APIs อาจไม่ได้มาตรฐานใน W3C ใครก็ตามที่มองหาวิธีแก้ปัญหาด้วยหยดควรใช้ความระมัดระวัง
ตามคำตอบ @Rick ซึ่งมีประโยชน์จริงๆ
คุณต้องสแคปสตริงdata
ถ้าคุณต้องการแชร์ด้วยวิธีนี้:
$('a.download').attr('href', 'data:application/csv;charset=utf-8,'+ encodeURI(data));
`ขอโทษฉันไม่สามารถแสดงความคิดเห็นในคำตอบของ @ Rick เนื่องจากชื่อเสียงที่ต่ำในปัจจุบันของฉันใน StackOverflow
ข้อเสนอแนะการแก้ไขถูกใช้ร่วมกันและการปฏิเสธ
เราสามารถใช้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: ค่าวัตถุ cyclic (Firefox) TypeError: การแปลง
โครงสร้างแบบวงกลมถึง JSON (Chrome และ Opera) TypeError: แบบวงกลม
ไม่รองรับการอ้างอิงค่าอาร์กิวเมนต์ (ขอบ)
การใช้ 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()
คุณยังสามารถดำเนินการอย่างหนึ่งดีกว่าเพียงแค่ URI ของ - ใช้ Chrome คุณยังสามารถที่จะแนะนำชื่อไฟล์จะใช้เวลาตามที่อธิบายไว้ในบล็อกโพสต์เกี่ยวกับการตั้งชื่อการดาวน์โหลดเมื่อใช้ยูริ
ฟังก์ชั่นด้านล่างนี้ทำงาน
private createDownloadableCsvFile(fileName, content) {
let link = document.createElement("a");
link.download = fileName;
link.href = `data:application/octet-stream,${content}`;
return link;
}
วิธีการต่อไปนี้ใช้งานได้ใน 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');
สำหรับฉันมันใช้งานได้อย่างสมบูรณ์แบบโดยมีชื่อไฟล์และนามสกุลเดียวกันกับการดาวน์โหลด
<a href={"data:application/octet-stream;charset=utf-16le;base64," + file64 } download={title} >{title}</a>
'title' เป็นชื่อไฟล์ที่มีนามสกุลคือsample.pdf
,,waterfall.jpg
ฯลฯ ..
'file64' เป็นเนื้อหาพื้นฐาน 64 เช่นนี้ Ww6IDEwNDAsIFNsaWRpbmdTY2FsZUdyb3VwOiAiR3JvdXAgQiIsIE1lZGljYWxWaXNpdEZsYXRGZWU6IDM1LCBEZW50YWxQYXltZW50UGVyY2VudGFnZTogMjUsIFByb2NlZHVyZVBlcmNlbnQ6IDcwLKCFfSB7IkdyYW5kVG90YWwiOjEwNDAsIlNsaWRpbmdTY2FsZUdyb3VwIjoiR3JvdXAgQiIsIk1lZGljYWxWaXNpdEZsYXRGZWUiOjM1LCJEZW50YWxQYXltZW50UGVyY2VudGFnZSI6MjUsIlByb2NlZHVyZVBlcmNlbnQiOjcwLCJDcmVhdGVkX0J5IjoiVGVycnkgTGVlIiwiUGF0aWVudExpc3QiOlt7IlBhdGllbnRO
ฉันจะใช้แท็กจากนั้นตั้งค่า<a></a>
href='path'
หลังจากนั้นให้วางภาพไว้ระหว่าง<a>
องค์ประกอบต่าง ๆ เพื่อให้ฉันสามารถมองเห็นได้ หากคุณต้องการคุณสามารถสร้างฟังก์ชั่นที่จะเปลี่ยนhref
เพื่อที่มันจะไม่ได้เป็นเพียงลิงค์เดียวกัน แต่เป็นแบบไดนามิก
ให้<a>
แท็กid
ด้วยถ้าคุณต้องการเข้าถึงด้วย javascript
เริ่มต้นด้วยเวอร์ชัน 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");
}
}
หากไฟล์มีข้อมูลข้อความเทคนิคที่ฉันใช้คือการใส่ข้อความลงในองค์ประกอบ textarea และให้ผู้ใช้เลือกมัน (คลิกใน textarea แล้ว ctrl-A) จากนั้นคัดลอกตามด้วยการวางลงในโปรแกรมแก้ไขข้อความ