Использование HTML5 / JavaScript для генерации и сохранения файла - PullRequest
296 голосов
/ 24 мая 2010

В последнее время я возился с WebGL и заставил работать читателя Collada.Проблема в том, что он довольно медленный (Collada - очень многословный формат), поэтому я собираюсь начать преобразование файлов в более простой в использовании формат (возможно, JSON).У меня уже есть код для синтаксического анализа файла в JavaScript, так что я могу также использовать его как мой экспортер!Проблема заключается в сохранении.

Теперь я знаю, что могу проанализировать файл, отправить результат на сервер и сделать так, чтобы браузер запросил файл обратно с сервера для загрузки.Но на самом деле сервер не имеет ничего общего с этим конкретным процессом, так зачем его привлекать?У меня уже есть содержимое нужного файла в памяти.Можно ли как-то представить пользователю загрузку с использованием чистого JavaScript?(Я сомневаюсь в этом, но с таким же успехом могу спросить ...)

И чтобы быть ясным: я не пытаюсь получить доступ к файловой системе без ведома пользователей!Пользователь предоставит файл (возможно, с помощью перетаскивания), скрипт преобразует файл в памяти, и пользователю будет предложено загрузить результат.Все это должно быть "безопасным" делом в отношении браузера.

[EDIT]: Я не упомянул об этом заранее, поэтому постеры, ответившие "Flash",Достаточно правильно, но часть того, что я делаю, - это попытка подчеркнуть, что можно сделать с помощью чистого HTML5 ... так что Flash в моем случае прямо.(Хотя это совершенно правильный ответ для любого, кто делает «настоящее» веб-приложение.) В таком случае мне кажется, что мне не повезло, если я не хочу привлекать сервер.В любом случае, спасибо!

Ответы [ 16 ]

257 голосов
/ 13 августа 2013

Простое решение для браузеров с поддержкой 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!');
246 голосов
/ 29 декабря 2010

ОК, создание данных: URI определенно помогает мне, благодаря Мэтью и Деннкстеру, указавшим эту возможность! Вот как я это делаю:

1) получить весь контент в строку, называемую «контентом» (например, создав его там изначально или прочитав innerHTML тега уже созданной страницы).

2) Построить URI данных:

uriContent = "data:application/octet-stream," + encodeURIComponent(content);

Будут ограничения по длине в зависимости от типа браузера и т. Д., Но, например, Firefox 3.6.12 работает по крайней мере до 256 КБ. Кодирование в Base64 вместо использования encodeURIComponent может сделать вещи более эффективными, но для меня это было нормально.

3) откройте новое окно и «перенаправьте» его на этот URI, чтобы запросить место загрузки моей страницы, созданной JavaScript:

newWindow = window.open(uriContent, 'neuesDokument');

Вот и все.

79 голосов
/ 19 мая 2012

HTML5 определил метод window.saveAs(blob, filename). Это не поддерживается ни одним браузером прямо сейчас. Но есть библиотека совместимости под названием FileSaver.js , которая добавляет эту функцию в большинство современных браузеров (включая Internet Explorer 10+). Internet Explorer 10 поддерживает метод navigator.msSaveBlob(blob, filename) ( MSDN ), который используется в FileSaver.js для поддержки Internet Explorer.

Я написал сообщение в блоге с более подробной информацией об этой проблеме.

42 голосов
/ 30 августа 2015

Сохранение больших файлов

Длинные URI данных могут вызвать проблемы с производительностью в браузерах. Другой вариант сохранения сгенерированных на стороне клиента файлов - поместить их содержимое в объект Blob (или File) и создать ссылку для загрузки, используя URL.createObjectURL(blob). Это возвращает URL, который можно использовать для получения содержимого большого двоичного объекта. Большой двоичный объект хранится в браузере до тех пор, пока по URL-адресу не будет вызван URL.revokeObjectURL() или документ, который его создал, будет закрыт. Большинство веб-браузеров поддерживают для URL-адресов объектов , Opera Mini - единственный, который их не поддерживает.

Принудительная загрузка

Если данные представляют собой текст или изображение, браузер может открыть файл, а не сохранять его на диск. Чтобы файл загружался по ссылке, вы можете использовать атрибут download. Однако не все веб-браузеры поддерживают для атрибута загрузки . Другой вариант - использовать application/octet-stream в качестве mime-типа файла, но это приводит к тому, что файл представляется в виде двоичного двоичного объекта, что особенно неудобно для пользователя, если вы не указали имя файла или не можете его указать. См. Также « Принудительно открывать всплывающее окно« Сохранить как ... »при открытии текстовой ссылки, щелкните PDF в HTML ».

Указание имени файла

Если большой двоичный объект создается с помощью конструктора файлов, вы также можете задать имя файла, но только несколько веб-браузеров (включая 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's 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>
32 голосов
/ 07 октября 2013
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();
}
25 голосов
/ 24 мая 2010

Взгляните на Doug Neiner Downloadify , который является JavaScript-интерфейсом на основе Flash для этого.

Downloadify - это небольшая библиотека JavaScript + Flash, которая позволяет создавать и сохранятьфайлов на лету, в браузере, без взаимодействия с сервером.

16 голосов
/ 26 августа 2016

Простое решение!

<a download="My-FileName.txt" href="data:application/octet-stream,HELLO-WORLDDDDDDDD">Click here</a>

Работает во всех современных браузерах.

10 голосов
/ 10 февраля 2014

Я использовал FileSaver (https://github.com/eligrey/FileSaver.js), и он отлично работает.
Например, я сделал эту функцию для экспорта журналов, отображаемых на странице.
Вы должны передать массив для создания экземпляра 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 голосов
/ 24 мая 2010

Вы можете сгенерировать URI данных . Однако существуют ограничения, специфичные для браузера.

8 голосов
/ 16 марта 2014

Я нашел два простых подхода, которые работают для меня.Во-первых, используя уже выбранный элемент 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>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...