Использование HTML5/JavaScript для генерации и сохранения файла
В последнее время я возился с WebGL и заставил работать читателя Collada. Проблема в том, что он довольно медленный (Collada - очень многословный формат), поэтому я собираюсь начать преобразование файлов в более простой в использовании формат (вероятно, JSON). У меня уже есть код для синтаксического анализа файла в JavaScript, так что я могу также использовать его как мой экспортер! Проблема в сохранении.
Теперь я знаю, что могу проанализировать файл, отправить результат на сервер и сделать так, чтобы браузер запросил файл с сервера для загрузки. Но на самом деле сервер не имеет ничего общего с этим конкретным процессом, так зачем его привлекать? У меня уже есть содержимое нужного файла в памяти. Можно ли как-то представить пользователю загрузку с использованием чистого JavaScript? (Я сомневаюсь в этом, но с таким же успехом могу спросить...)
И чтобы быть ясным: я не пытаюсь получить доступ к файловой системе без ведома пользователей! Пользователь предоставит файл (возможно, с помощью перетаскивания), скрипт преобразует файл в памяти, и пользователю будет предложено загрузить результат. Все это должно быть "безопасной" деятельностью, если речь идет о браузере.
[РЕДАКТИРОВАТЬ]: Я не упомянул об этом заранее, поэтому постеры, ответившие "Flash", достаточно действительны, но часть того, что я делаю, - это попытка подчеркнуть, что можно сделать с чистым HTML5... так что Flash прямо в моем случае. (Хотя это совершенно правильный ответ для любого, кто делает "настоящее" веб-приложение.) В таком случае мне кажется, что мне не повезло, если я не хочу привлекать сервер. Спасибо, в любом случае!
Ответы
Ответ 1
ОК, создавая данные: URI определенно делает трюк для меня, благодаря Мэтью и Деннкстеру, указывающим на этот вариант! Вот в основном, как я это делаю:
1) получить все содержимое в строку под названием "контент" (например, создав ее там изначально или путем чтения innerHTML тега уже построенной страницы).
2) Создайте URI данных:
uriContent = "data:application/octet-stream," + encodeURIComponent(content);
Будут ограничения длины в зависимости от типа браузера и т.д., но, например, Firefox 3.6.12 работает до 256K. Кодирование в Base64 вместо использования encodeURIComponent может сделать вещи более эффективными, но для меня это нормально.
3) откройте новое окно и переадресовывайте его в этот URI, чтобы указать местоположение загрузки моей страницы, сгенерированной JavaScript:
newWindow = window.open(uriContent, 'neuesDokument');
Что это.
Ответ 2
Простое решение для готовых браузеров HTML5...
function download(filename, text) {
var pom = document.createElement('a');
pom.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text));
pom.setAttribute('download', filename);
if (document.createEvent) {
var event = document.createEvent('MouseEvents');
event.initEvent('click', true, true);
pom.dispatchEvent(event);
}
else {
pom.click();
}
}
Использование
download('test.txt', 'Hello world!');
Ответ 3
HTML5 определил метод window.saveAs(blob, filename)
. Он не поддерживается ни одним браузером прямо сейчас. Но есть библиотека совместимости, называемая FileSaver.js, которая добавляет эту функцию в большинство современных браузеров (включая Internet Explorer 10+). Internet Explorer 10 поддерживает метод navigator.msSaveBlob(blob, filename)
(MSDN), который используется в FileSaver.js для поддержки Internet Explorer.
Я написал сообщение с более подробной информацией об этой проблеме.
Ответ 4
Сохранение больших файлов
Длинные URI данных могут приводить к проблемам с производительностью в браузерах. Другой вариант сохранения созданных на стороне клиента файлов состоит в том, чтобы поместить их содержимое в объект Blob (или File) и создать ссылку для загрузки, используя URL.createObjectURL(blob)
. Это возвращает URL-адрес, который можно использовать для извлечения содержимого блоба. URL.revokeObjectURL()
хранится внутри браузера, пока не будет URL.revokeObjectURL()
в URL-адресе, или созданный документ закрыт. Большинство веб-браузеров поддерживают URL-адреса объектов, Opera Mini - единственная, которая их не поддерживает.
Принуждение загрузки
Если данные представляют собой текст или изображение, браузер может открыть файл, а не сохранять его на диск. Чтобы заставить файл загружаться при нажатии ссылки, вы можете использовать атрибут download
. Однако не все веб-браузеры поддерживают атрибут загрузки. Другой вариант - использовать application/octet-stream
в качестве файла mime-type, но это приводит к тому, что файл представляется как двоичный blob, который особенно непригоден для пользователя, если вы не укажете или не можете указать имя файла. См. Также " Сила, чтобы открыть" Сохранить как... "всплывающее окно в текстовой ссылке нажмите для pdf в HTML ".
Указание имени файла
Если blob создается с помощью конструктора файлов, вы также можете указать имя файла, но только для нескольких браузеров (включая Chrome и Firefox) есть поддержка конструктора файлов. Имя файла также может быть указано как аргумент атрибута download
, но это зависит от тонны соображений безопасности. Internet Explorer 10 и 11 предоставляет свой собственный метод msSaveBlob, чтобы указать имя файла.
Пример кода
var file;
var data = [];
data.push("This is a test\n");
data.push("Of creating a file\n");
data.push("In a browser\n");
var properties = {type: 'text/plain'}; // Specify the file mime-type.
try {
// Specify the filename using the File constructor, but ...
file = new File(data, "file.txt", properties);
} catch (e) {
// ... fall back to the Blob constructor if that isn't supported.
file = new Blob(data, properties);
}
var url = URL.createObjectURL(file);
document.getElementById('link').href = url;
<a id="link" target="_blank" download="file.txt">Download</a>
Ответ 5
function download(content, filename, contentType)
{
if(!contentType) contentType = 'application/octet-stream';
var a = document.createElement('a');
var blob = new Blob([content], {'type':contentType});
a.href = window.URL.createObjectURL(blob);
a.download = filename;
a.click();
}
Ответ 6
Взгляните на Doug Neiner Downloadify, который является интерфейсом JavaScript на основе Flash для этого.
Downloadify - это небольшая библиотека JavaScript + Flash, которая позволяет генерировать и сохранять файлы "на лету" в браузере без взаимодействия с сервером.
Ответ 7
Простое решение!
<a download="My-FileName.txt" href="data:application/octet-stream,HELLO-WORLDDDDDDDD">Click here</a>
Ответ 8
Вы можете сгенерировать URI данных. Однако существуют ограничения, зависящие от браузера.
Ответ 9
Я использовал FileSaver (https://github.com/eligrey/FileSaver.js), и он отлично работает.
Например, я сделал эту функцию для экспорта журналов, отображаемых на странице.
Вы должны передать массив для instanciation Blob, так что я просто, возможно, не написал это правильно, но он работает для меня.
На всякий случай, будьте осторожны с заменой: это синтаксис, чтобы сделать это глобальным, иначе он заменит только первый, который он встретит.
exportLogs : function(){
var array = new Array();
var str = $('#logs').html();
array[0] = str.replace(/<br>/g, '\n\t');
var blob = new Blob(array, {type: "text/plain;charset=utf-8"});
saveAs(blob, "example.log");
}
Ответ 10
Я нашел два простых подхода, которые работают для меня. Сначала, используя уже нажатый элемент a
и вводя данные загрузки. А во-вторых, генерируем элемент a
с данными загрузки, выполняя a.click()
и удаляя его снова. Но второй подход работает только при вызове действия щелчка пользователя. (Некоторые) Браузерный блок click()
из других контекстов, например, при загрузке или срабатывании после таймаута (setTimeout).
<!DOCTYPE HTML>
<html>
<head>
<meta charset="UTF-8">
<script type="text/javascript">
function linkDownload(a, filename, content) {
contentType = 'data:application/octet-stream,';
uriContent = contentType + encodeURIComponent(content);
a.setAttribute('href', uriContent);
a.setAttribute('download', filename);
}
function download(filename, content) {
var a = document.createElement('a');
linkDownload(a, filename, content);
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
}
</script>
</head>
<body>
<a href="#" onclick="linkDownload(this, 'test.txt', 'Hello World!');">download</a>
<button onclick="download('test.txt', 'Hello World!');">download</button>
</body>
</html>
Ответ 11
Вот ссылка на метод URI данных, предложенный Мэтью, он работал на сафари, но не очень хорошо, потому что я не мог установить тип файла, он становится сохраненным как "неизвестный", а затем мне нужно вернуться туда позже и изменить это для просмотра файла...
http://www.nihilogic.dk/labs/canvas2image/
Ответ 12
Вы можете использовать localStorage. Это эквивалент файлов cookie Html5. Кажется, он работает на Chrome и Firefox, но на Firefox, мне нужно было загрузить его на сервер. То есть, тестирование непосредственно на моем домашнем компьютере не сработало.
Я работаю над примерами HTML5. Перейдите к http://faculty.purchase.edu/jeanine.meyer/html5/html5explain.html
и прокрутите до лабиринта. Информация для восстановления лабиринта хранится с использованием localStorage.
Я пришел в эту статью, ища HTML5 JavaScript для загрузки и работы с XML файлами. Это то же самое, что и старый html и JavaScript????
Ответ 13
Как уже упоминалось, File API, а также FileWriter и FileSystem API-интерфейсы могут использоваться для хранения файлов на клиентской машине из контекста вкладки/окна браузера.
Однако есть несколько вещей, относящихся к последним двум API, о которых вы должны знать:
- Реализации API-интерфейсов в настоящее время существуют только в браузерах на основе хрома (Chrome и Opera)
- Оба API были сняты со стандартного трека W3C 24 апреля 2014 года и на данный момент являются собственностью
- Удаление (теперь запатентованных) API-интерфейсов от реализации браузеров в будущем - это возможность
- песочница (расположение на диске, за пределами которого файлы не могут произвести никакого эффекта) используется для хранения файлов, созданных с помощью API
- Используется виртуальная файловая система (структура каталогов, которая необязательно существует на диске в той же форме, что и при доступе из браузера) представляет файлы, созданные с помощью API
Вот простые примеры того, как API используются, прямо или косвенно, в тандеме, чтобы сделать это:
BakedGoods *
bakedGoods.get({
data: ["testFile"],
storageTypes: ["fileSystem"],
options: {fileSystem:{storageType: Window.PERSISTENT}},
complete: function(resultDataObj, byStorageTypeErrorObj){}
});
Использование необработанных файлов, API FileWriter и FileSystem
function onQuotaRequestSuccess(grantedQuota)
{
function saveFile(directoryEntry)
{
function createFileWriter(fileEntry)
{
function write(fileWriter)
{
var dataBlob = new Blob(["Hello world!"], {type: "text/plain"});
fileWriter.write(dataBlob);
}
fileEntry.createWriter(write);
}
directoryEntry.getFile(
"testFile",
{create: true, exclusive: true},
createFileWriter
);
}
requestFileSystem(Window.PERSISTENT, grantedQuota, saveFile);
}
var desiredQuota = 1024 * 1024 * 1024;
var quotaManagementObj = navigator.webkitPersistentStorage;
quotaManagementObj.requestQuota(desiredQuota, onQuotaRequestSuccess);
Хотя API-интерфейсы FileSystem и FileWriter больше не соответствуют стандартным трекам, их использование может быть оправдано в некоторых случаях, на мой взгляд, потому что:
- Возобновленный интерес у недействующих поставщиков браузеров может вернуть их обратно.
- Проникновение на рынок реализующих (на основе хромовых) браузеров является высоким.
- Google (основной вклад в Chromium) не дал и не закончил API API
Однако, если "некоторые случаи" охватывают ваши собственные, вы должны решить.
* BakedGoods поддерживается не кем иным, как этим парнем прямо здесь:)
Ответ 14
Вот учебник по экспорту файлов в формате ZIP:
Перед тем, как начать работу, есть библиотека для сохранения файлов, имя библиотеки - fileSaver.js. Здесь вы можете найти эту библиотеку. Давайте начнем. Теперь включите необходимые библиотеки:
<script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.1.4/jszip.min.js" type="text/javascript"></script>
<script type="text/javascript" src="https://fastcdn.org/FileSaver.js/1.1.20151003/FileSaver.js" ></script>
Скопируйте этот код, и этот код загрузит zip файл с файлом hello.txt, имеющим контент Hello World. Если все работает нормально, это загрузит файл.
<script type="text/javascript">
var zip = new JSZip();
zip.file("Hello.txt", "Hello World\n");
zip.generateAsync({type:"blob"})
.then(function(content) {
// see FileSaver.js
saveAs(content, "file.zip");
});
</script>
Это загрузит файл с именем file.zip. Вы можете прочитать здесь: http://www.wapgee.com/story/248/guide-to-create-zip-files-using-javascript-by-using-jszip-library
Ответ 15
Этот поток был неоценим, чтобы понять, как сгенерировать двоичный файл и предложить загрузить указанный файл, все в коде клиента без сервера.
Первым шагом для меня было создание двоичного двоичного объекта из данных, которые я сохранял. Существует множество примеров для выполнения этого для одного двоичного типа, в моем случае у меня есть двоичный формат с несколькими типами, который вы можете передать в виде массива для создания большого двоичного объекта.
saveAnimation: function() {
var device = this.Device;
var maxRow = ChromaAnimation.getMaxRow(device);
var maxColumn = ChromaAnimation.getMaxColumn(device);
var frames = this.Frames;
var frameCount = frames.length;
var writeArrays = [];
var writeArray = new Uint32Array(1);
var version = 1;
writeArray[0] = version;
writeArrays.push(writeArray.buffer);
//console.log('version:', version);
var writeArray = new Uint8Array(1);
var deviceType = this.DeviceType;
writeArray[0] = deviceType;
writeArrays.push(writeArray.buffer);
//console.log('deviceType:', deviceType);
var writeArray = new Uint8Array(1);
writeArray[0] = device;
writeArrays.push(writeArray.buffer);
//console.log('device:', device);
var writeArray = new Uint32Array(1);
writeArray[0] = frameCount;
writeArrays.push(writeArray.buffer);
//console.log('frameCount:', frameCount);
for (var index = 0; index < frameCount; ++index) {
var frame = frames[index];
var writeArray = new Float32Array(1);
var duration = frame.Duration;
if (duration < 0.033) {
duration = 0.033;
}
writeArray[0] = duration;
writeArrays.push(writeArray.buffer);
//console.log('Frame', index, 'duration', duration);
var writeArray = new Uint32Array(maxRow * maxColumn);
for (var i = 0; i < maxRow; ++i) {
for (var j = 0; j < maxColumn; ++j) {
var color = frame.Colors[i][j];
writeArray[i * maxColumn + j] = color;
}
}
writeArrays.push(writeArray.buffer);
}
var blob = new Blob(writeArrays, {type: 'application/octet-stream'});
return blob;
}
Следующий шаг - заставить браузер предложить пользователю загрузить этот BLOB-объект с заранее заданным именем.
Все, что мне было нужно, это именованная ссылка, которую я добавил в HTML5, и которую я мог использовать повторно, чтобы переименовать исходное имя файла. Я держал это скрытым, так как ссылка не нуждается в отображении.
<a id="lnkDownload" style="display: none" download="client.chroma" href="" target="_blank"></a>
Последний шаг - предложить пользователю загрузить файл.
var data = animation.saveAnimation();
var uriContent = URL.createObjectURL(data);
var lnkDownload = document.getElementById('lnkDownload');
lnkDownload.download = 'theDefaultFileName.extension';
lnkDownload.href = uriContent;
lnkDownload.click();
Ответ 16
пытаться
let a = document.createElement('a');
a.href = "data:application/octet-stream,"+encodeURIComponent('"My DATA"');
a.download = 'myFile.json';
a.click();