Categorie
Javascript Programmazione

{JS} File API: FileReader

Cos’è l’API FileReader?

Da sempre l’accesso ad un file, per accesso intendiamo il caricamento e la lettura, ha rappresentato una limitazione di JavaScript.
Il motivo aveva ragioni di sicurezza; prima delle possibili soluzioni che vedremo in seguito per aggirare questa limitazione si provvedeva con l’inviare il file al server per poi ricaricarlo per visualizzare il suo contenuto o informazioni sullo stesso.

Con l’avvento di HTML5 ora possiamo caricare e leggere un file direttamente dal browser.

HTML5 ed il caricamento di file

Con HTML5 possiamo permettere all’utente di caricare un file direttamente sul browser.
Esistono due possibilità:

  • utilizzare il tag <input>
  • utilizzare il drag-and-drop.

<input>

<input type="file" id="caricamentoFiles" multiple>

 L’elemento <input> in HTML5 consente all’utente di selezionare un file dal proprio File System (locale).
Valorizzando l’attributo “type” con “file” ed utlizzando l’attributo empy “multiple” consentiamo la selezione di più file.
E inoltre possibile limitare il tipo di file attraverso l’attributo “accept”.

<input type="file" id="caricamentoFiles" accept=".jpg, .jpeg, .png" multiple>

Drag and Drop

Possiamo sfruttare anche il drag-and-drop per consentire al cliente di caricare file sul browser; per farlo dovremo prevedere una area/riquadro dove consentire il rilascio:

<div id="areaRilascioFile">
<p>Trascina e rilascia il file per caricare</p>
<p id="notificaFile"></p>
</div>
<style>
#areaRilascioFile{ border: 1px dotted white; display: flex;  justify-content: center; height: 100px; align-items: center; border-radius: 5px; width: 50%; flex-direction: column;}
#notificaFile{color:green;}
</style>

Trascina e rilascia il file per caricare


Dovremo ora provvedere alla gestione degli eventi del D&D:

var areaRilascio = document.getElementById("areaRilascioFile");
var notificaFile = document.getElementById("notificaFile");

areaRilascio.ondragenter = function(event){
event.stopImmediatePropagation();
event.preventDefault();};

areaRilascio.ondragover = function(event){
event.stopImmediatePropagation();
event.preventDefault();};

areaRilascio.ondrop = function(event){
event.stopImmediatePropagation();
	event.preventDefault();
	filesCaricati = event.dataTransfer.files;
        notificaFile.innerHTML = `Hai caricato n. ${filesCaricati.length} files.`;
}

I gestori dragenter e dragover impediscono il comportamento predefinito dell’operazione, senza queste istruzioni il trascinamento dei file sulla pagina causerebbe il loro caricamento all’interno della finestra del browser.

Il gestore dell’evento drop tramite la proprietà dataTransfer dell’oggetto event, “Drag&DropEvent”,  mostra il numero di file trascinati all’interno dell’area.

File API

Attraverso la FILE API e le sue funzionalità a disposizione possiamo avere accesso alla lista dei file selezionati/caricati in lettura.

Per accedere alla lista dei file caricati nel caso del Drang&Drop sfrutteremo le proprietà dell’event object “event.dataTransfer.files”

...
filesCaricati = event.dataTransfer.files;
...

Nell’esempio precedente abbiamo definito la variabile “filesCaricati” omettendo “var”, definendo di fatto una variabile globale; questo ci consentirà di accedere alla stessa e quindi alla lista dei file caricati esternamente alla funzione.

Anche per l’elemento <input> è possibile recuperare l’elenco dei file selezionati dall’utente:

var fileCaricatiInput = document.getElementById('caricamentoFiles').files;

Sarà sufficiente creare una nuova variabile “fileCaricatiInput” recuperare nuovamente l’elemento mediante l’id ed utilizzare la proprietà “.files”

Quel che ci è restituito dalla proprietà file è un oggetto detto “File Object”; nel caso di una multi-selezione si parlerà di “Object FileList” mentre nel caso di un file singolo si parlerà di “Object File”.

L’API File definisce tre tipi di oggetto di tipo file:

OggettoDescrizione
FileListRappresenta semplicemente una lista di file
FileRappresenta un singolo file
FileReaderÈ l’oggetto che consente l’accesso in lettura al contenuto del file

L’oggetto FileList/File

Principalmente gli oggetti “File” e “FileList” sono utilizzati per le i metadati di una lista di file o di un file singolo.

La proprietà “.files” restituisce l’oggetto “File” o “FileList”.
Abbiamo a disposizione tre proprietà per accedere alle informazioni sui file.

ProprietàDescrizione
nameNome del file
sizeDimensione del file espressa in byte
typeIl tipo MIMEType del file; se non è possibile determinarlo restituisce una stringa vuota

Il caso più particolare è quello dell’oggetto “FileList”; per visionare le informazioni dei file caricati dovremo provvedere con il ciclare gli elementi dell’oggetto per visionare le proprietà dei file caricati:

var fileCaricatiInput = document.getElementById('caricamentoFiles').files;
for (var i=0; i<fileCaricatiInput.length; i++) {
	file = fileCaricatiInput[i];
	console.log(` Nome file: ${file.name} Dimensione: ${file.size} byte Tipo: ${file.type}`);
}

L’oggetto FileReader

L’oggetto “FileReader”, invece, è utilizzato per leggere il contenuto dei file caricati.
 È possibile indicare a “FileReader” di leggere un file come un buffer di array , un URL di dati o un testo .

Per farlo abbiamo 3 metodi asincroni:

MetodoDescrizione
reader.readAsText(file)il metodo legge il file come testo
reader.readAsDataURL(file)il metodo legge il file come un url di dati
reader.readAsArrayBuffer(file)il metodo legge il file come buffer di array

Per leggere il contenuto di un campo <input> dovremo metterci in ascolto di eventuali cambiamenti su di esso:

<input id="campoFile" type="file" onchange="letturaFile()">
<img id="attesaImmagine" src="#">

Colleghiamo all’input-elemento mediante codice in-line la funzione “letturaFile()” da eseguire al momento del cambiamento di stato (evento “onchange”), che sta ad indicare l’effettivo caricamento di un file da parte dell’utente.

var campoFile = document.getElementById('campoFile');
var immagine = document.getElementById('attesaImmagine');

function letturaFile(){
fileCaricato = campoFile.files[0];

var reader = new FileReader();
reader.readAsDataURL(fileCaricato);

reader.onload = function(event){
immagine.src = reader.result; }

}

Mappiamo i campi presenti nel DOM, ovvero il campo <input> e l’elemento <img>, attualmente vuoto.
All’interno della funzione “letturaFile()” da scatenare al momento del cambio di stato del campo input, recuperiamo il file caricato attraverso la proprietà “.files()”.
Successivamente creiamo un nuovo lettore dei contenuti, “new Reader”, ed indichiamo di interpretare la lettura di tale dato come un “url” mediante il metodo “.readAsDataURL()”.
In fine attraverso la gestione di uno degli eventi disponibili per i readers, “load”, indichiamo di inserire l’url generato nell’attributo “src” dell’elemento <img>.

L’evento “load” è un evento gestibile appartenente agli eventi dedicati ai “new Reader” e sta ad indicare di completare un operazione non appena il file sarà completamente letto.

Note: la proprietà ".files" restituisce un oggetto che sarà sempre di tipo "FileList" indipendentemente se indiciamo o meno di poter caricare file multipli. Il che significa che dovremo, nel caso di file singolo, recuperare l'oggetto-file contenuto nella "FileList" con indice [0].

Eventi dei Readers

Nell’esempio precedente abbiamo utilizzato l’evento “load” del lettore di contenti “new Readers”.
Abbiamo a disposizione due eventi dedicati per gestire la lettura dei contenuti:

EventoDescrizione
loadindica il momento del completamento del caricamento
progressindicare il punto di progressione della lettura
Evento “load”

L’evento “load” fornisce, nè più nè meno, di quanto visto sopra.

Evento “progress”

L’evento “progress” è utile quando si leggono file di grandi dimensioni, e per fornire un po’ di UX

L’evento possiede due proprietà utili alla gestione del caricamento progressivo:

ProprietàDescrizione
event.loadedfornisce informazioni relative ai dati letti progressivamente
event.totalfornisce informazioni su l’interezza dei dati da leggere progressivamente
var campoFileImmagine = document.getElementById('campoFileImmagine');
var elementoImmagine = document.getElementById('attesaImmagine');
var progresso = document.getElementById('progresso');

function letturaFileImmagine(){

fileImmagineCaricato = campoFileImmagine.files[0];

var readerImmagine = new FileReader();
readerImmagine.readAsDataURL(fileImmagineCaricato);

readerImmagine.onload = function(event){
elementoImmagine.src = readerImmagine.result;
}

readerImmagine.onprogress = function(event){
if(event.loaded && event.total){
var percentuale = (event.loaded / event.total) * 100;
progresso.innerHTML=`Caricamento: ${Math.round(percentuale)} %`;
}
}

}

Tutto è rimasto pressoché invariato per l’evento “load”.
Per la gestione dell’evento “progress” abbiamo previsto un’ulteriore elemento per mostrare la stringa di caricamento.
Abbiamo verificato l’esistenza delle proprietà “event.loaded” ed “event.total” e calcolato attraverso di essere la percentuale di progressione da inserire dinamicamente nell’elemento con id “progresso”.

L’evento “progress” viene generato periodicamente durante la lettura dei dati da parte di “FileReader”.

Maggiore sarà il peso dell’immagine è più sarà visibile la percentuale di caricamento.

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *