Чи є спосіб вказати запропоноване ім'я файлу при використанні даних: URI?


225

Якщо, наприклад, ви переходите за посиланням:

data:application/octet-stream;base64,SGVsbG8=

Браузер запропонує вам завантажити файл, що складається з даних, що зберігаються як base64, у самому гіперпосиланні. Чи можна запропонувати ім'я за замовчуванням у розмітці? Якщо ні, чи є рішення JavaScript?


можливо, не пов’язаний із цим питанням, але я пропоную використовувати & blob's & URL.createObjectURL, якщо це не перешкода для сервера чи старого веб-переглядача
Нескінченний

3
Деякі браузери підтримують додатковий параметр "ім'я" data:application/pdf;name=document.pdf;base64,BASE64_DATA_ENCODED
медіатипу

У мене виникла проблема з Firefox pdf.js, яка, як правило, зависає в деяких випадках, якщо вона не може витягти ім'я файлу з даних uri. дивіться stackoverflow.com/questions/45585921/…
Бернхард

@mems Які браузери підтримують параметр "ім'я"? Чи можете ви вказати мені якусь довідкову документацію? (мій google-fu зірвав мене).
TheAddonDepot

@DimuDesigns Принаймні Firefox на той час. Схоже, це вже не так. Це пов'язано з параметром "ім'я" MIME Content-Type (! = Content-Disposition) (не в RFC?)
пам’яті

Відповіді:


158

Використовуйте downloadатрибут:

<a download='FileName' href='your_url'>

Живий приклад на html5-demos.appspot.com / ... .

В даний час працює на Chrome, Firefox, Edge, Opera та настільних Safari, але не iOS Safari або IE11.


3
@BioDesign: Він працює навіть із даними: URI у хромі. Дивіться: jsfiddle.net/pYpqW
Senseful

6
але ви не можете це зробити window.location.replace. якщо ви, наприклад, хочете створити дані: uri або дані, згенеровані window.URL.createObjectURLфайлом, та завантажити їх у файл, вам доведеться створити <a> та натиснути на нього: jsfiddle.net/flyingsheep/wpQtH (ні, $(...).click()не працює)
літаючі вівці

1
Тільки якщо весь браузер був схожий на Chrome ... [зітхання]
вуличне світло

6
@flyingsheep, $('<a href="data:text/plain,Test" download="test.txt">')[0].click()здається, працює добре тут (Chrome 23) (зауважте: я використовував нативний clickметод , а не метод jQuery). Демо: jsfiddle.net/2zsRW
Rob W

1
@flyingsheep здається, що вони застосовують політику одного походження в Firefox "У Firefox 20 цей атрибут шанується лише за посилання на ресурси з однаковим походженням". developer.mozilla.org/en-US/docs/Web/HTML/Element/a У моєму тестуванні Chrome не має цього обмеження.
Вільям Денніс

62

Chrome робить це дуже просто сьогодні:

function saveContent(fileContents, fileName)
{
    var link = document.createElement('a');
    link.download = fileName;
    link.href = 'data:,' + fileContents;
    link.click();
}

Ідк, що всі ці інші відповіді говорять про це спрацювали при першій спробі в Chrome 30.
Майкл Дж. Калкінс

2
Це зараз, але це було не завжди так просто. Багато з цих відповідей - з років тому. А також вони працюють для інших браузерів.
Холф

7
Зверніться до http://caniuse.com/#feat=download для повного списку сумісності браузера.
tixastronauta

2
@tixastronauta: Незважаючи на інформацію на цій сторінці, я не працюю в моєму Firefox 44. Добре працює в Chrome. 48
Луїс А. Флорит

Привіт @Holf Чи є також спосіб додати тип файлу чи розширення або його так само просто, як spceficy це як ім'я файлу?
Fraccier

51

Тільки HTML: використовуйте downloadатрибут:

<a download="logo.gif" href="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7">Download transparent png</a>


Тільки Javascript: ви можете зберегти будь-який URI даних за допомогою цього коду:

function saveAs(uri, filename) {
  var link = document.createElement('a');
  if (typeof link.download === 'string') {
    link.href = uri;
    link.download = filename;

    //Firefox requires the link to be in the body
    document.body.appendChild(link);
    
    //simulate click
    link.click();

    //remove the link when done
    document.body.removeChild(link);
  } else {
    window.open(uri);
  }
}

var file = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7'
saveAs(file, 'logo.gif');

Chrome, Firefox та Edge 13+ використовуватимуть вказане ім’я файлу.

IE11, Edge 12 та Safari 9 (які не підтримують downloadатрибут ) завантажують файл зі своїм іменем за замовчуванням або вони просто відображатимуть його на новій вкладці, якщо він підтримує тип файлу: зображення, відео, аудіофайли ,…


Обидва демонстраційні версії для мене працюють у Chrome 38 (але вони повинні працювати в Chrome 14+)
fregante

Для більш повного рішення я пропоную використовувати downloadjsв npm
fregante

Це працює для мене, але сторінка браузера оновлюється після цього. Цікаво, як запобігти цьому?

1
Не працює в хромі для розміру файлу> 2 Мб через обмеження chrome stackoverflow.com/questions/695151/…
Pranav Singh

Межа належить до data:URI, про що йдеться у питанні. Ця відповідь також працює з Blobs, і все, що ще має URI
fregante

40

За даними RFC 2397 , ні, немає.

Там також не спостерігається ніяких атрибутів з <a>елемента , який ви можете використовувати або.

Однак згодом HTML5 ввів downloadатрибут <a>елемента, хоча на момент написання підтримка не є універсальною (наприклад, немає підтримки MSIE)


9
друге речення було правильним на момент написання, але вже не . на сьогоднішній день він все ще не широко впроваджений.
літаючі вівці

дивіться цей коментар для отримання додаткової інформації :)
літаючі вівці

@flyingsheep, він буде широко застосовуватися.
Pacerier

1
це було не 3 роки тому, коли я написав цей коментар
літаючі вівці

Якщо файл настільки довгий, завантаження не вдається
deFreitas

21

Я трохи подивився джерела Firefox у netwerk / протокол / дані / nsDataHandler.cpp

обробник даних аналізує лише вміст / тип та схему, і виглядає, якщо в рядку є "; base64"

rfc специфікує не ім'я файлу, і принаймні firefox не обробляє для нього ім'я файлу, код генерує випадкове ім'я плюс ".part"

Я також перевірив журнал firefox

[b2e140]: DOCSHELL 6e5ae00 InternalLoad data:application/octet-stream;base64,SGVsbG8=
[b2e140]: Found extension '' (filename is '', handling attachment: 0)
[b2e140]: HelperAppService::DoContent: mime 'application/octet-stream', extension ''
[b2e140]: Getting mimeinfo from type 'application/octet-stream' ext ''
[b2e140]: Extension lookup on '' found: 0x0
[b2e140]: Ext. lookup for '' found 0x0
[b2e140]: OS gave back 0x43609a0 - found: 0
[b2e140]: Searched extras (by type), rv 0x80004005
[b2e140]: MIME Info Summary: Type 'application/octet-stream', Primary Ext ''
[b2e140]: Type/Ext lookup found 0x43609a0

цікаві файли, якщо ви хочете переглянути джерела mozilla:

data uri handler: netwerk/protocol/data/nsDataHandler.cpp
where mozilla decides the filename: uriloader/exthandler/nsExternalHelperAppService.cpp
InternalLoad string in the log: docshell/base/nsDocShell.cpp

Я думаю, ви можете зараз зупинити пошук рішення, тому що я підозрюю, що його немає :)

як помічено в цій темі html5 має downloadатрибут, він працює також у firefox 20 http://www.whatwg.org/specs/web-apps/current-work/multipage/links.html#attr-hyperlink-download


3
Класно! Хоча я не обов'язково згоден, що Firefox є найвищим авторитетом у тому, що існує. :)
Глено

14

Наступний фрагмент Javascript працює в Chrome, використовуючи новий атрибут 'скачати' посилання та імітуючи клацання.

function downloadWithName(uri, name) {
  var link = document.createElement("a");
  link.download = name;
  link.href = uri;
  link.click();
}

І наступний приклад показує, що це використання:

downloadWithName("data:,Hello%2C%20World!", "helloWorld.txt")

1
У Firefox це не працює, я додав нижче розширену відповідь із сумісністю з Fx.
fregante

12

Немає.

Вся мета полягає в тому, що це потік даних, а не файл. Джерело даних не повинно мати ніяких знань про користувацький агент, який обробляє його як файл ... і це не так.


6
Мета data:- перетворити блок внутрішніх даних у формат URL без необхідності їх зчитування з джерела, заснованого на протоколі. Посилання у відповіді @ silex показує, що можливість запропонувати вподобане ім'я для запису вважається корисною, навіть якщо вона ще не реалізована.
Альнітак

1
@Alnitak: Корисно? Абсолютно. Технічно доцільно? Досі не переконаний. :)
Гонки легкості по орбіті

3
@Tomalak враховує різницю між завантаженням даних та їх збереженням - лише тому, що крапка закодована в рядку даних: URL не означає, що воно не повинно мати бажаного імені для його збереження.
Alnitak

4
Але ваша думка про це "цілі цілі" неправильна. data:був спеціально придуманий, щоб дозволити (невеликий) вбудований вміст відображатись у форматі згорнутих URL-адрес, щоб його можна було використовувати в таких речах, як теги зображень без окремого запиту HTTP. HTML говорить, що вміст img srcатрибута повинен бути URL-адресою, тому саме це створило RFC 2397. Немає "джерела даних".
Альнітак

6
@Alnitak: Саме так. Немає джерела даних. Немає контексту. URI - це дані.
Гонки легкості на орбіті

9

ви можете додати атрибут завантаження до елемента прив’язки.

зразок:

<a download="abcd.cer"
    href="data:application/stream;base64,MIIDhTC......">down</a>

5

Подивіться за цим посиланням: http://lists.w3.org/Archives/Public/uri/2010Feb/0069.html

Цитата:

Він навіть працює (як у, не викликає проблем) з; base64 наприкінці
так (як мінімум в Opera):

дані: текст / звичайний; charset = utf-8; заголовки = вміст-диспозиція% 3A% 20прикладення% 3B% 20файл% 3D% 22з% 20spaces.txt% 22% 0D% 0AContent-Language% 3A% 20en; base64,4oiaDQo% 3D

Також є інша інформація у решті повідомлень дискусії.


на жаль, це не завантажується.
Джеймс Хоурі

7
ця дискусія була запропонована для розширення формату URI даних - вона не була реалізована.
Альнітак

Реалізовано чи ні, при існуючій підтримці довільних параметрів це було б чудово.
Ден Лугг

5

Використовуючи сервісних працівників , це, нарешті, можливо в справжньому розумінні.

  1. Створіть підроблену URL-адресу. Наприклад /saveAs/myPrettyName.jpg
  2. Використовуйте URL в <a href, <img src, window.open (url) абсолютно все, що можна зробити з "реальною" URL-адресою.
  3. Всередині працівника вловлюйте подію вибору та відповідайте правильними даними.

Тепер браузер запропонує myPrettyName.jpg, навіть якщо користувач відкриє файл на новій вкладці і намагається зберегти його там. Це буде точно так, як би файл прийшов із сервера.

// In the service worker
self.addEventListener( 'fetch', function(e)
{
    if( e.request.url.startsWith( '/blobUri/' ) )
    {
        // Logic to select correct dataUri, and return it as a Response
        e.respondWith( dataURLAsRequest );
    }
});

1
Цікаво! Підтримка здається досить неглибоко зараз, хоча: caniuse.com/#feat=serviceworkers
tuomassalo

Чи є спосіб "відповісти" іншим прямим URL-адресою файлу?
Юліан Онофрей

4

У коді Google є крихітний спосіб вирішення проблеми, який працював на мене:

http://code.google.com/p/download-data-uri/

Він додає форму з даними в ній, подає її, а потім видаляє форму знову. Хаккі, але це зробило роботу для мене. Потрібен jQuery.

Цей потік з’явився в Google перед сторінкою Google Code, і я подумав, що може бути корисним і тут, щоб мати посилання.


Цікавий сценарій, але він вимагає від сервера отримати відповідь та відправити його назад правильно? jsfiddle.net/hZySf
Джеймс

Я не впевнений, звідки генерується файл .. це файл зберігається в коді base64? (Я не надто знайомий з base64)
ліхтарик

@streetlight: "файл" (тобто дані) генерується Javascript. Контекст цього проекту (і, мабуть, більшість тут) передбачає, що у вас є певний спосіб передати потрібні дані в змінну JS. Різниця полягає в тому, що замість того, щоб представляти його користувачеві через data:...URI, цей скрипт створює форму для розміщення його на сервері. Тоді сервер, ймовірно, повторює його як відповідь HTTP на завантаження (тобто з відповідним заголовком Content-Disposition із зазначенням назви файла).
Анджей Дойл

4

Ось версія jQuery, заснована на версії Holf і працює з Chrome і Firefox, тоді як, здається, його версія працює лише з Chrome. Це трохи дивно додати щось тілу, щоб це зробити, але якщо хтось має кращий варіант, я все за це.

var exportFileName = "export-" + filename;
$('<a></a>', {
    "download": exportFileName,
    "href": "data:," + JSON.stringify(exportData, null,5),
    "id": "exportDataID"
}).appendTo("body")[0].click().remove();

1
З jQuery 1.11 я отримую виняток через .remove (). Я $().appendTo()variable.click(); variable.remove()
обійшов

@ p0lar_bear ви повинні отримати це виняток з будь-якого jQuery, тому що отримання [0]будь-якого "jQuery елемента" має повернути перший DOM елемент, який він представляє, що по суті "виводить вас з" jQuery.
drzaus

Ви на самому справі не потрібно , щоб додати / видалити елемент взагалі - див коментарі на stackoverflow.com/a/17311705/1037948
drzaus

3

Це наче хакі, але я раніше був у тій же ситуації. Я динамічно генерував текстовий файл у JavaScript і хотів надати його для завантаження, кодуючи його з URI даних.

Це можливо при незначному великому втручанні користувача. Створіть посилання<a href="data:...">right-click me and select "Save Link As..." and save as "example.txt"</a> . Як я вже говорив, це неелегантно, але воно працює, якщо вам не потрібно професійне рішення.

Це може бути менш болючим, використовуючи спалах, щоб спершу скопіювати ім'я у буфер обміну. Звичайно, якщо ви дозволите собі використовувати Flash або Java (зараз я думаю, що з меншою підтримкою браузера?), Можливо, ви можете знайти інший спосіб зробити це.


Це не є рішенням і не відповідає тому, про що просили. Вибачте.
jcolebrand

7
Lol @ "втручання незначного користувача". Змусити користувача зробити все для вас не є "незначним втручанням користувача".
Гонки легкості по орбіті

Поєднайте це з stackoverflow.com/questions/17311645/…, щоб запустити створене посилання, і вам не потрібно втручання користувача. Ви можете вказати атрибут HTML5,download щоб запропонувати ім'я, як згадується у багатьох інших відповідях .
drzaus

Це чудове рішення для Safari. Використовуйте Modernizr, щоб виявити, коли атрибут завантаження не підтримується, і оновити текст посилання!
littledynamo

2

Цей працює з Firefox 43.0 (старіший не перевірений):

dl.js:

function download() {
  var msg="Hello world!";
  var blob = new File([msg], "hello.bin", {"type": "application/octet-stream"});

  var a = document.createElement("a");
  a.href = URL.createObjectURL(blob);

  window.location.href=a;
}

dl.html

<html lang="en" xmlns="http://www.w3.org/1999/xhtml">

<head>
    <meta charset="utf-8"/>
    <title>Test</title>
    <script type="text/javascript" src="dl.js"></script>
</head>

<body>
<button id="create" type="button" onclick="download();">Download</button>
</body>
</html>

Якщо натиснути кнопку, то для завантаження запропоновано файл з назвою hello.bin . Трюком є ​​використання файлу замість Blob .

довідка: https://developer.mozilla.org/de/docs/Web/API/File


0
var isIE = /*@cc_on!@*/false || !!document.documentMode; // At least IE6
var sessionId ='\n';
var token = '\n';
var caseId = CaseIDNumber + '\n';
var url = casewebUrl+'\n';
var uri = sessionId + token + caseId + url;//data in file
var fileName = "file.i4cvf";// any file name with any extension
if (isIE)
    {
            var fileData = ['\ufeff' + uri];
            var blobObject = new Blob(fileData);
            window.navigator.msSaveOrOpenBlob(blobObject, fileName);
    }
    else //chrome
    {
        window.requestFileSystem = window.requestFileSystem || window.webkitRequestFileSystem;
         window.requestFileSystem(window.TEMPORARY, 1024 * 1024, function (fs) {
            fs.root.getFile(fileName, { create: true }, function (fileEntry) { 
                fileEntry.createWriter(function (fileWriter) {
                    var fileData = ['\ufeff' + uri];
                    var blob = new Blob(fileData);
                    fileWriter.addEventListener("writeend", function () {
                        var fileUrl = fileEntry.toURL();
                        var link = document.createElement('a');
                        link.href = fileUrl;
                        link.download = fileName;
                        document.body.appendChild(link);
                        link.click();
                        document.body.removeChild(link);
                    }, false);
                    fileWriter.write(blob);
                }, function () { });
            }, function () { });
         }, function () { });
    }

1
pls, додайте більш детальне пояснення до своєї відповіді - stackoverflow.com/help/how-to-answer
Себастьян Брош

1
ця відповідь - сміття
Джонатан Тейлор

-2

Ви насправді можете досягти цього в Chrome і FireFox.

Спробуйте наступний URL, він завантажить код, який був використаний.

data:text/html;base64,PGEgaHJlZj0iZGF0YTp0ZXh0L2h0bWw7YmFzZTY0LFBHRWdhSEpsWmowaVVGVlVYMFJCVkVGZlZWSkpYMGhGVWtVaUlHUnZkMjVzYjJGa1BTSjBaWE4wTG1oMGJXd2lQZ284YzJOeWFYQjBQZ3BrYjJOMWJXVnVkQzV4ZFdWeWVWTmxiR1ZqZEc5eUtDZGhKeWt1WTJ4cFkyc29LVHNLUEM5elkzSnBjSFErIiBkb3dubG9hZD0idGVzdC5odG1sIj4KPHNjcmlwdD4KZG9jdW1lbnQucXVlcnlTZWxlY3RvcignYScpLmNsaWNrKCk7Cjwvc2NyaXB0Pg==
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.