Создайте файл в памяти для загрузки пользователем, а не через сервер
Можно ли как-нибудь создать текстовый файл на стороне клиента и предложить пользователю загрузить его без какого-либо взаимодействия с сервером? Я знаю, что не могу писать напрямую на их машину (безопасность и все остальное), но могу ли я создать и предложить им сохранить ее?
25 ответов
Вы можете использовать данные URI. Поддержка браузера варьируется; см. википедию. Пример:
<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.
Простое решение для 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!');
Все вышеперечисленные решения не работают во всех браузерах. Вот что в итоге работает на 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.revokeObjectURL после удаления elem
, Согласно документам для URL.createObjectURL:
Каждый раз, когда вы вызываете createObjectURL(), создается новый URL-адрес объекта, даже если вы уже создали его для того же объекта. Каждый из них должен быть освобожден путем вызова URL.revokeObjectURL(), когда они вам больше не нужны. Браузеры выпустят их автоматически, когда документ выгружен; однако для оптимальной производительности и использования памяти, если есть безопасные моменты, когда вы можете явно выгружать их, вы должны сделать это.
Все вышеприведенные примеры прекрасно работают в 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);
Я счастливо использую FileSaver.js. Его совместимость довольно хорошая (IE10+ и все остальное), и он очень прост в использовании:
var blob = new Blob(["some text"], {
type: "text/plain;charset=utf-8;",
});
saveAs(blob, "thing.txt");
Это работает для меня (Chrome 86):
function download(content, mimeType, filename){
var a = document.createElement('a')
var blob = new Blob([content], {type: mimeType})
var url = URL.createObjectURL(blob)
a.setAttribute('href', url)
a.setAttribute('download', filename)
a.click()
}
Здесь вы можете увидеть скрипку:https://jsfiddle.net/Stelios2020/ukmf5304/6/
Следующий метод работает в 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 не поддерживает его в целях безопасности.
С другой стороны, в IE есть API для сохранения большого двоичного объекта, который можно использовать для создания и загрузки файлов.
Мы можем использовать API- адрес URL, в частности URL.createObjectURL(), и API- интерфейс Blob для кодирования и загрузки чего угодно.
Если ваша загрузка небольшая, это нормально работает:
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 лучше создать элемент ссылки с параметрами загрузки и вызвать щелчок.
Обратите внимание, что элемент ссылки не добавлен к документу, но щелчок все равно работает! Таким образом можно создать загрузку многих сотен Мо.
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
ссылка в аргументе значения не поддерживается (Edge)
Используя 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()
Пакет js-file-download с https://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')
Это решение извлекается непосредственно из репозитория 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: Скачать модуль заставки
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);
}
// Start file download.
download("hello.txt","This is the content of my file :)");
Исходная статья: https://ourcodeworld.com/articles/read/189/how-to-create-a-file-and-generate-a-download-with-javascript-in-the-browser-without-a-server
Если вы просто хотите преобразовать строку, которая будет доступна для загрузки, вы можете попробовать это с помощью jQuery.
$('a.download').attr('href', 'data:application/csv;charset=utf-8,' + encodeURI(data));
Решение, которое работает на 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")
Как упоминалось ранее, 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();
На основании ответа @Rick, который был действительно полезен.
Вы должны отпустить строку data
если вы хотите поделиться этим так:
$('a.download').attr('href', 'data:application/csv;charset=utf-8,'+ encodeURI(data));
`Извините, я не могу комментировать ответ @ Рика из-за моей низкой репутации в Stackru.
Предложение по редактированию было передано и отклонено.
По состоянию на апрель 2014 года API-интерфейсы FileSytem могут быть не стандартизированы в W3C. Думаю, любой, кто смотрит на решение с помощью blob, должен быть осторожен.
Вы даже можете сделать один лучше, чем просто URI - используя Chrome, вы также можете предложить имя файла, как описано в этом сообщении в блоге о присвоении имени загрузке при использовании URI.
Эта функция ниже работает.
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');
Загрузите файл с расширениями или без расширений в примере, я использую JSON. Вы можете добавить свои данные и расширения. Вы можете использовать здесь «MAC-Addresses.json» по своему желанию. Если вы хотите добавить расширение, добавьте туда, иначе просто напишите имя файла без расширений.
let myJson = JSON.stringify(yourdata);
let element = document.createElement('a');
element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(myJson));
element.setAttribute('download', 'MAC-Addresses.json');
element.style.display = 'none';
document.body.appendChild(element);
element.click();
document.body.removeChild(element);
Я бы использовал <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");
}
}
Для меня это сработало идеально, с тем же именем файла и расширения загружается
<a href={"data:application/octet-stream;charset=utf-16le;base64," + file64 } download={title} >{title}</a>
title - это имя файла с расширением, т.е. sample.pdf
, waterfall.jpg
, так далее..
"file64" - это содержимое base64, например, Ww6IDEwNDAsIFNsaWRpbmdTY2FsZUdyb3VwOiAiR3JvdXAgQiIsIE1lZGljYWxWaXNpdEZsYXRGZWU6IDM1LCBEZW50YWxQYXltZW50UGVyY2VudGFnZTogMjUsIFByb2NlZHVyZVBlcmNlbnQ6IDcwLKCFfSB7IkdyYW5kVG90YWwiOjEwNDAsIlNsaWRpbmdTY2FsZUdyb3VwIjoiR3JvdXAgQiIsIk1lZGljYWxWaXNpdEZsYXRGZWUiOjM1LCJEZW50YWxQYXltZW50UGVyY2VudGFnZSI6MjUsIlByb2NlZHVyZVBlcmNlbnQiOjcwLCJDcmVhdGVkX0J5IjoiVGVycnkgTGVlIiwiUGF0aWVudExpc3QiOlt7IlBhdGllbnRO
Если файл содержит текстовые данные, я использую метод, который заключается в том, чтобы поместить текст в элемент textarea и сделать так, чтобы пользователь выделил его (щелкните текстовое поле, затем ctrl-A), а затем скопируйте и вставьте в текстовый редактор.
Это действительно возможно - используйте Flash.
Вы можете либо сгенерировать контент с помощью JS, а затем инициализировать некоторые флэш-переменные, либо просто сделать все внутри флэш-фильма.
Пожалуйста, посмотрите на это для некоторых важных замечаний.