FileReader
File
I følge W3C File API [1] gir et File-object oss tilgang til følgende egenskaper:
- size
- name
- lastModifiedDate
- type (mimetype)
Merk at name er bare selve filnavnet. Vi har ikke tilgang til filstien.
Vi lar brukeren identifisere filer ved hjelp av browse og drag-drop.
Browse
Vi kan gjøre slik:
<fieldset style="width:300px;padding:20px"> <legend>finn 1 textfil</legend> <input type="file" autocomplete="off" id="txtfile" accept="text/*"/> <output id="outtxtfile"> </output> </fieldset>
Merk accept attributten. Denne sier hvilke filer som vises når vi browser. Vi kan angi dette på flere måter:
- file extension: accept=".text" eller flere file extensions: accept=".text,.csv"
- mediatype [3] : accept="text/*", eller accept="text/html" eller accept="image/*,video/*"
Følgende eventhandler kjører når brukeren har valgt fil:
function handleFileSelect1(evt) { var f = evt.target.files[0]; result=[]; result.push(encodeURI(f.name),'(',f.type || 'n/a', ') : ',f.size,' bytes') document.getElementById('outtxtfile').innerHTML = result.join(''); }
Metoden er plantet slik når siden lastes:
document.getElementById('txtfile') .addEventListener('change', handleFileSelect1, false);
Vi kan tillate valg av flere filer ved å sette attributte multiple i input elementet.
Dersom vi forsøker å skrive: s=JSON.stringify(f)), der f er et filobjekt, så får vi 0. Dette er altså ikke noen måte å finne ut mer om fila, f.eks. filstien.
Drag
<fieldset id="dropfiles1" style="width:300px;padding:20px"> <legend>drag filer hit</legend> <output id="list"></output> </fieldset>
Følgende eventhandlere kjører når brukeren har droppet filen(e):
function handleFileSelect2(evt) { evt.stopPropagation(); evt.preventDefault(); var files = evt.dataTransfer.files; // FileList var result = []; for (var i = 0, f; f = files[i]; i++) { result.push('<li><strong>', escape(f.name), '</strong> (', f.type || 'n/a', ') - ', f.size, ' bytes', ' , modified: ', f.lastModifiedDate ? f.lastModifiedDate.toLocaleDateString() : 'n/a','</li>'); } document.getElementById('list').innerHTML = '<ul>' + result.join('') + '</ul>'; } function handleDragOver(evt) { evt.stopPropagation(); evt.preventDefault(); evt.dataTransfer.dropEffect = 'copy'; }
Metoden er plantet slik når siden lastes:
var dropZone = document.getElementById('dropfiles'); dropZone.addEventListener('dragover', handleDragOver, false); dropZone.addEventListener('drop', handleFileSelect2, false);
FileReader
Når websiden nå har fått tilgang til informasjon om filer på vår harddisk kan vi lese disse filene med FileReader. En fil kan oppfattes enten som en Blob eller en File. En Blob betrakter fila som en serie med bytes( 0,255) og gir mulighet for selektere byte-sekvenser. FileReader gir oss tilgang til følgende metoder for File eller Blob:
- abort()
- readAsArrayBuffer(Blob|File)
- readAsBinaryString(Blob|File)
- readAsDataURL(Blob|File)
- readAsText(Blob|File,encoding)
Merk at vi selvsagt ikke får lov til å skrive. Vi kan lese filene på litt forskjellig måte og vi kan abortere en leseoperasjon. FileReader har attributter (error, readyState, result) og eventhandlere (onabort, onerror, onload, onloadstart, onloadend, onprogress) som tilsammen gir oss kontroll.
Dette gir oss en åpen situasjon og det er vanskelig å vise vanntette eksempler på hva det er mulig å foreta seg siden det avhenger av hva du, som leser, finner på når det gjelder å lokalisere filer på din harddisk. Nedenfor finner du noen eksempler på noen øvelser som du kan forsøke deg på. Eksemplene bruker browse, men det kunne like godt vært gjort ved drag.
Eksempel 1
Vi forsøker først å laste opp en ren textfil (.txt), og vise den i en pre-tag. Vi bruker browse.
<fieldset style="width:300px;padding:20px"> <legend>finn 1 textfil</legend> <input type="file" autocomplete="off" id="txtfile3" accept=".txt"/> <output id="outtxtfile3"> </output> </fieldset> <pre style="border-style:solid;border-width:thin" id="filecontent3"> </pre>
Følgende eventhandler kjører når brukeren har valgt fil:
function handleFileSelect3(evt) { var f = evt.target.files[0]; found=[]; found.push(encodeURI(f.name),'(',f.type || 'n/a', ') : ', f.size,' bytes') document.getElementById('outtxtfile3').innerHTML = found.join(''); txtType = /text.*/; if(!f.type.match(txtType)){ document.getElementById('filecontent3').innerHTML= "bad MIME type"; return; } reader=new FileReader(); reader.onload=function(e) { document.getElementById('filecontent3').innerHTML= reader.result; } reader.readAsText(f); }
Metoden er plantet slik når siden lastes:
document.getElementById('txtfile3') .addEventListener('change', handleFileSelect3, false);
Vi har da kontroll over innholdet i fila brukeren har vist oss og vi kan ta innholdet og manipulere det etter ønske eller sende det, eventuelt sammen med noe annet, i en AJAX-request. Det vi ikke kan gjøre er å skrive noe tilbake til brukerens harddisk. Et interessant eksperiment vil kanskje være om vi kunne lagre innholdet med f.eks. localStorage slik at det dukker opp når brukeren melder seg igjen. Kanskje ikke så lurt med mye informasjon, siden localStorage tross alt har begrenset kapasitet.
Eksempel 2
I dette eksempelet lar vi brukeren, deg, velge flere bildefiler og viser fram thumbnails.
<fieldset style="width:350px;padding:20px"> <legend>finn bildefil(er)</legend> <input type="file" autocomplete="off" id="imgfile" multiple="true" accept="image/*"/> <output id="outimgfiles"> </output> </fieldset> <div style="border-style:solid;border-width:thin" id="filecontent4"> </div>
Følgende eventhandler kjører når brukeren har valgt filer:
function handleFileSelect4(evt) { evt.stopPropagation(); evt.preventDefault(); var files = evt.target.files; // FileList var found = []; for (var i = 0, f; f = files[i]; i++) { found.push('<li><strong>', escape(f.name), '</strong> (', f.type || 'n/a', ') - ', f.size, ' bytes</li>'); } document.getElementById('outimgfiles').innerHTML = '<ul>' + found.join('') + '</ul>'; var txtType = /image.*/; var showElt=document.getElementById("filecontent4"); showElt.innerHTML=""; for (var i = 0, f; f = files[i]; i++) { if(!f.type.match(txtType)) continue; var img = document.createElement("img"); img.classList.add("thumb"); img.file = f; showElt.appendChild(img); reader=new FileReader(); reader.onload=(function(theImg) { return function(e) { theImg.src = e.target.result; }; })(img); reader.readAsDataURL(f); } }
Metoden er plantet slik når siden lastes:
document.getElementById('imgfile') .addEventListener('change', handleFileSelect4, false);
Når bilder som lastes på denne måte legges ut på websiden legges de ikke i det formatet vi vanligvis bruker:
<img class="thumb" src="bilde.png" alt="bilde"/>
De legges ut slik:
<img class="thumb" src="data:image/gif;base64,R0lGODlh…BACxA0...."></img>
(der dataene er forkortet)