Filesaver.js

Library


 

Quante volte ci siamo imbattuti nella necessità di salvare file dal lato client per le nostre webapp? Grazie alla libreria di "Eli Gray" ciò diviene semplice e sicuro. Solitamente quando si desidera generare un file tramite il codice JavaScript è necessario passare dal server per poi riprendere i dati con una intestazione. Questa modalità presuppone la presenza di un server nonchè la necessità di connettersi in rete. Filesaver.js implementa la funzionalità per salvare file lato client tramite l'api W3C FileSaver con il metodo saveAs(data, filename). Essa è valida per tutti i moderni browser ed è possibile generare praticamente qualsiasi tipo di file.

Per verificare che il browser supporti questa procedura il codice da eseguire è semplicemente:

try {
    var isFileSaverSupported = !!new Blob;
} catch (e) {}

La semplicità di utilizzo di questa libreria è una nota di merito che semplifica molto la vita di un programmatore che si imbatte in queste problematiche. Salvare un file client to client con javascript diventa immediato come eseguire questa funzione:

canvas.toBlob(function(blob) {
    saveAs(blob, filename);
});

Per generare un file è necessario inizializzare una API BLob, se questa non fosse supportata dal browser è possibile implementarla tramite Blob.js come indicato in seguito.

Vediamo un esempio che illustra la modalità di salvataggio di un documento XHTML con saveAs():

saveAs(
      new Blob(
          [(new XMLSerializer).serializeToString(document)]
        , {type: "application/xhtml+xml;charset=" + document.characterSet}
    )
    , "document.xhtml"
);

E' altresì possibile salvare dei dati binari o ArrayBuffer tipizzati in un blob:

var
      buffer = new ArrayBuffer(8) // alloca 8 byte
    , data = new DataView(buffer)
;
 // Puoi scrivere uint8 / 16 / 32s e float32 / 64s in visualizzazioni dei dati
data.setUint8 (0, 0x01);
data.setUint16(1, 0x2345);
data.setUint32(3, 0x6789ABCD);
data.setUint8 (7, 0xEF);
 
saveAs(new Blob([buffer], {type: "example/binary"}), "data.dat");
// I contenuti di data.dat sono <01 23 45 67 89 AB CD EF> 

In sintesi vediamo la sintassi generica per utilizzare questa libreria:

FileSaver saveAs(Blob/File data, opzionale DOMString nomefile, opzionale Boolean disableAutoBOM)

Di seguito veidamo alcuni esempi per il salvataggio di vari tipi di file:

//Require
 
var FileSaver = require ( ' file-saver ' );
 
// Salvataggio testo

var blob = new Blob ([ " ciao, mondo! " ], {type : " text / plain; charset = utf-8 " });
FileSaver .  saveAs (blob, " ciao mondo.txt " ); 

//Salvataggio immagini canvas

var canvas = document.getElementById("my-canvas"), ctx = canvas.getContext("2d");

canvas.toBlob(function(blob) {

saveAs(blob, "immagine.png");

});

//Salvataggio diretto di file

var file = nuovo File ([ " ciao, mondo! " ], " ciao mondo.txt " , {type : " text / 

plain; charset = utf-8 " });

FileSaver .  saveAs (file); 

Ed ecco la libreria da includere nei nostri progetti:

/* FileSaver.js
* A saveAs() FileSaver implementation.
* 1.3.8

/*! @source https://purl.eligrey.com/github/FileSaver.js/blob/master/src/FileSaver.js */

export var saveAs = saveAs || (function(view) {
"use strict";
// IE &lt;10 is explicitly unsupported
if (typeof view === "undefined" || typeof navigator !== "undefined" &amp;&amp; /MSIE [1-9]\./.test(navigator.userAgent)) {
return;
}
var
doc = view.document
// only get URL when necessary in case Blob.js hasn't overridden it yet
, get_URL = function() {
return view.URL || view.webkitURL || view;
}
, save_link = doc.createElementNS("https://www.w3.org/1999/xhtml", "a")
, can_use_save_link = "download" in save_link
, click = function(node) {
var event = new MouseEvent("click");
node.dispatchEvent(event);
}
, is_safari = /constructor/i.test(view.HTMLElement) || view.safari
, is_chrome_ios =/CriOS\/[\d]+/.test(navigator.userAgent)
, setImmediate = view.setImmediate || view.setTimeout
, throw_outside = function(ex) {
setImmediate(function() {
throw ex;
}, 0);
}
, force_saveable_type = "application/octet-stream"
// the Blob API is fundamentally broken as there is no "downloadfinished" 
, arbitrary_revoke_timeout = 1000 * 40 // in ms
, revoke = function(file) {
var revoker = function() {
if (typeof file === "string") { // file is an object URL
get_URL().revokeObjectURL(file);
} else { // file is a File
file.remove();
}};
setTimeout(revoker, arbitrary_revoke_timeout);
}
, dispatch = function(filesaver, event_types, event) {
event_types = [].concat(event_types);
var i = event_types.length;
while (i--) {
var listener = filesaver["on" + event_types[i]];
if (typeof listener === "function") {
try {
listener.call(filesaver, event || filesaver);
} catch (ex) {
throw_outside(ex);
}}}}
, auto_bom = function(blob) {
// prepend BOM for UTF-8 XML and text/* types (including HTML)
// note: your browser will automatically convert UTF-16 U+FEFF to EF BB BF
if (/^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(blob.type)) {
return new Blob([String.fromCharCode(0xFEFF), blob], {type: blob.type});
}
return blob;
}
, FileSaver = function(blob, name, no_auto_bom) {
if (!no_auto_bom) {
blob = auto_bom(blob);
}// First try a.download, then web filesystem, then object URLs
var
filesaver = this
, type = blob.type
, force = type === force_saveable_type
, object_url
, dispatch_all = function() {
dispatch(filesaver, "writestart progress write writeend".split(" "));
}
// on any filesys errors revert to saving with object URLs
, fs_error = function() {
if ((is_chrome_ios || (force &amp;&amp; is_safari)) &amp;&amp; view.FileReader) {
// Safari doesn't allow downloading of blob urls
var reader = new FileReader();
reader.onloadend = function() {
var url = is_chrome_ios ? reader.result : reader.result.replace(/^data:[^;]*;/, 'data:attachment/file;');
var popup = view.open(url, '_blank');
if(!popup) view.location.href = url;
url=undefined; // release reference before dispatching
filesaver.readyState = filesaver.DONE;
dispatch_all();
};
reader.readAsDataURL(blob);
filesaver.readyState = filesaver.INIT;
return;
}
// don't create more object URLs than needed
if (!object_url) {
object_url = get_URL().createObjectURL(blob);
}
if (force) {
view.location.href = object_url;
} else {
var opened = view.open(object_url, "_blank");
if (!opened) {
view.location.href = object_url;
}}
filesaver.readyState = filesaver.DONE;
dispatch_all();
revoke(object_url);
};
filesaver.readyState = filesaver.INIT;

if (can_use_save_link) {
object_url = get_URL().createObjectURL(blob);
setImmediate(function() {
save_link.href = object_url;
click(save_link);
dispatch_all();
revoke(object_url);
filesaver.readyState = filesaver.DONE;
}, 0);
return;
}
fs_error();
}
, FS_proto = FileSaver.prototype
, saveAs = function(blob, name, no_auto_bom) {
return new FileSaver(blob, name || blob.name || "download", no_auto_bom);
};
// IE 10+ (native saveAs)
if (typeof navigator !== "undefined" &amp;&amp; navigator.msSaveOrOpenBlob) {
return function(blob, name, no_auto_bom) {
name = name || blob.name || "download";
if (!no_auto_bom) {
blob = auto_bom(blob);
}
return navigator.msSaveOrOpenBlob(blob, name);
};}
// todo: detect chrome extensions &amp; packaged apps
//save_link.target = "_blank";
FS_proto.abort = function(){};
FS_proto.readyState = FS_proto.INIT = 0;
FS_proto.WRITING = 1;
FS_proto.DONE = 2;

FS_proto.error =
FS_proto.onwritestart =
FS_proto.onprogress =
FS_proto.onwrite =
FS_proto.onabort =
FS_proto.onerror =
FS_proto.onwriteend =
null;

return saveAs;
}(
typeof self !== "undefined" &amp;&amp; self
|| typeof window !== "undefined" &amp;&amp; window
|| this
));