JavaScript: создать и сохранить файл
У меня есть данные, которые я хочу записать в файл, и открыть диалоговое окно файла, чтобы пользователь мог выбрать, куда сохранить файл. Было бы замечательно, если бы он работал во всех браузерах, но он должен работать в Chrome. Я хочу сделать все это на стороне клиента.
В основном я хочу знать, что добавить в эту функцию:
saveFile: function(data)
{
}
Когда функция принимает данные, пользователь выбирает место для сохранения файла и создает файл в этом месте с этими данными.
Использование HTML тоже хорошо, если это помогает.
10 ответов
Очень незначительное улучшение кода с помощью Awesomeness01 (нет необходимости в теге привязки) с добавлением, как предложено trueimage (поддержка IE):
// Function to download data to a file
function download(data, filename, type) {
var file = new Blob([data], {type: type});
if (window.navigator.msSaveOrOpenBlob) // IE10+
window.navigator.msSaveOrOpenBlob(file, filename);
else { // Others
var a = document.createElement("a"),
url = URL.createObjectURL(file);
a.href = url;
a.download = filename;
document.body.appendChild(a);
a.click();
setTimeout(function() {
document.body.removeChild(a);
window.URL.revokeObjectURL(url);
}, 0);
}
}
Проверено на корректную работу в Chrome, FireFox и IE10.
В Safari данные открываются в новой вкладке, и нужно будет вручную сохранить этот файл.
function download(text, name, type) {
var a = document.getElementById("a");
var file = new Blob([text], {type: type});
a.href = URL.createObjectURL(file);
a.download = name;
}
<a href="" id="a">click here to download your file</a>
<button onclick="download('file text', 'myfilename.txt', 'text/plain')">Create file</button>
И тогда вы загрузите файл, поместив атрибут загрузки в тег привязки.
Причина, по которой мне это нравится больше, чем создание URL-адреса данных, заключается в том, что вам не нужно создавать длинный длинный URL-адрес, вы можете просто создать временный URL-адрес.
Этот проект на github выглядит многообещающе:
https://github.com/eligrey/FileSaver.js
FileSaver.js реализует интерфейс W3C saveAs() FileSaver в браузерах, которые его изначально не поддерживают.
Также посмотрите демо здесь:
Выбор места для сохранения файла перед его созданием невозможен. Но возможно, по крайней мере в Chrome, генерировать файлы, используя только JavaScript. Вот мой старый пример создания файла CSV. Пользователю будет предложено загрузить его. Это, к сожалению, не очень хорошо работает в других браузерах, особенно в IE.
<!DOCTYPE html>
<html>
<head>
<title>JS CSV</title>
</head>
<body>
<button id="b">export to CSV</button>
<script type="text/javascript">
function exportToCsv() {
var myCsv = "Col1,Col2,Col3\nval1,val2,val3";
window.open('data:text/csv;charset=utf-8,' + escape(myCsv));
}
var button = document.getElementById('b');
button.addEventListener('click', exportToCsv);
</script>
</body>
</html>
setTimeout("create('Hello world!', 'myfile.txt', 'text/plain')");
function create(text, name, type) {
var dlbtn = document.getElementById("dlbtn");
var file = new Blob([text], {type: type});
dlbtn.href = URL.createObjectURL(file);
dlbtn.download = name;
}
<a href="javascript:void(0)" id="dlbtn"><button>click here to download your file</button></a>
Для последнего браузера, такого как Chrome, вы можете использовать File API, как в этом руководстве:
window.requestFileSystem = window.requestFileSystem || window.webkitRequestFileSystem;
window.requestFileSystem(window.PERSISTENT, 5*1024*1024 /*5MB*/, saveFile, errorHandler);
function download(text, name, type) {
var a = document.getElementById("a");
var file = new Blob([text], {type: type});
a.href = URL.createObjectURL(file);
a.download = name;
}
<a href="" id="a">click here to download your file</a>
<button onclick="download('file text', 'myfilename.json', 'text/json')">Create file</button>
Я думаю, что это может работать и с файлами json, если вы измените тип mime.
function SaveBlobAs(blob, file_name) {
if (typeof navigator.msSaveBlob == "function")
return navigator.msSaveBlob(blob, file_name);
var saver = document.createElementNS("http://www.w3.org/1999/xhtml", "a");
var blobURL = saver.href = URL.createObjectURL(blob),
body = document.body;
saver.download = file_name;
body.appendChild(saver);
saver.dispatchEvent(new MouseEvent("click"));
body.removeChild(saver);
URL.revokeObjectURL(blobURL);
}
Пробовал это в консоли, и это работает.
var aFileParts = ['<a id="a"><b id="b">hey!</b></a>'];
var oMyBlob = new Blob(aFileParts, {type : 'text/html'}); // the blob
window.open(URL.createObjectURL(oMyBlob));
Вы не можете сделать это чисто в Javascript. Javascript, работающий в браузерах, пока не имеет достаточных разрешений (были предложения) по соображениям безопасности.
Вместо этого я бы рекомендовал использовать Downloadify:
Крошечная библиотека javascript + Flash, которая позволяет создавать и загружать текстовые файлы без взаимодействия с сервером.
Здесь вы можете увидеть простую демонстрацию, в которой вы предоставляете контент и можете проверить функциональность сохранения / отмены / обработки ошибок.
Попробуйте использовать это, он загрузит файл, и все, что вам нужно сделать, это отредактировать атрибуты onclick.
function download(text, name, type) {
var a = document.getElementById("a");
a.style.display = "block";
var file = new Blob([text], {type: type});
a.href = URL.createObjectURL(file);
a.download = name;
}
#a { display: none; }
<a href="" id="a" download>click here to download your file</a>
<button onclick="download('file text', 'myfilename.txt', 'text/plain')">Create file</button>
StreamSaver - это альтернатива для сохранения очень больших файлов без необходимости хранить все данные в памяти.
На самом деле он эмулирует все, что серверная доза при сохранении файла, но все стороны клиента с обслуживающим работником.
Вы можете либо получить средство записи и вручную записать в него Uint8Array, либо направить двоичный readableStream в поток для записи
Есть несколько примеров демонстрации:
- Как сохранить несколько файлов в формате ZIP
- передача readableStream из, например,
Response
или жеblob.stream()
в StreamSaver - запись вручную в поток записи при вводе чего-либо
- или перекодировать видео / аудио
Вот пример в простейшей форме:
const fileStream = streamSaver.createWriteStream('filename.txt')
new Response('StreamSaver is awesome').body
.pipeTo(fileStream)
.then(success, error)
Если вы хотите сохранить большой двоичный объект, вы просто конвертируете его в readableStream
new Response(blob).body.pipeTo(...) // response hack
blob.stream().pipeTo(...) // feature reference
Для Chrome и Firefox я использовал чисто JavaScript-метод.
(Мое приложение не может использовать пакет, такой как Blob.js
потому что он обслуживается специальным движком: DSP с сервером WWWeb, забитым небольшим пространством для чего-либо.)
function FileSave(sourceText, fileIdentity) {
var workElement = document.createElement("a");
if ('download' in workElement) {
workElement.href = "data:" + 'text/plain' + "charset=utf-8," + escape(sourceText);
workElement.setAttribute("download", fileIdentity);
document.body.appendChild(workElement);
var eventMouse = document.createEvent("MouseEvents");
eventMouse.initMouseEvent("click", true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
workElement.dispatchEvent(eventMouse);
document.body.removeChild(workElement);
} else throw 'File saving not supported for this browser';
}
Примечания, предостережения и ласка-слова:
- Я имел успех с этим кодом в клиентах Chrome и Firefox, работающих в средах Linux (Maipo) и Windows (7 и 10).
- Однако если
sourceText
больше, чем МБ, Chrome иногда (только иногда) застревает в своей загрузке без каких-либо признаков сбоя; Firefox до сих пор не демонстрировал такого поведения. Причиной может быть некоторое ограничение BLOB-объектов в Chrome. Честно говоря, я просто не знаю; если у кого-то есть идеи как исправить (или хотя бы обнаружить), пожалуйста, пишите. Если происходит сбой при загрузке, когда браузер Chrome закрыт, он генерирует такую диагностику, как - Этот код не совместим с Edge или Internet Explorer; Я не пробовал Opera или Safari.
Javascript имеет API-интерфейс FileSystem. Если вы можете справиться с тем, чтобы эта функция работала только в Chrome, хорошей отправной точкой будет: http://www.html5rocks.com/en/tutorials/file/filesystem/.