Kirjautuminen

Haku

Tehtävät

Keskustelu: Nettisivujen teko: Javascript FileReader

ilkkak [07.09.2015 13:11:58]

#

Vähän ongelmia tiedostojen lukemisessa omalta koneelta www-sivulle javascriptillä.

FileReader rajapinnassa on onload -määritys, jossa parametrina tulee tiedot ladattavasta tiedostosta mm. nimi
Toisaalta on määritetty myös onprogress -metodi, jonka avulla voi monitoroida latauksen etenemistä.

Ongelma; Jos ladataan useita tiedostoja yhdellä valinnalla (<input/> - multiple attribuutti), onprogress-metodi ei tiedä, mitä tiedostoa ollaan lataamassa. Sille välitetään progressevent -tyyppinen parametri, jossa ei ole muuta informaatiota kuin latauksen suuruus ja ladattu tavumäärä.

Tarkoituksena olisi tehdä kullekin ladattavalle tiedostolle oma editysmislaatikko, jota päivitetään sitä mukaa kuin lataus etenee. Koska onprogress -metodi ei tiedä, mitä tiedostoa lataus koskee, ei siis oikean edistymislaatikon päivitys onnistu.

Metabolix [07.09.2015 17:22:32]

#

Eikö FileReader lue vain yhtä tiedostoa kerralla? Sinulla pitäisi siis olla jokaiselle tiedostolle oma FileReader. Alla on yksinkertainen esimerkki.

<!DOCTYPE html>
<meta charset="UTF-8" />
<style>
dd {
	font-family: monospace;
}
</style>
<script>
function load(f) {
	var dl = document.getElementById("output"), dt, dd_bar, dd_bytes;
	dl.appendChild(dt = document.createElement("dt"));
	dl.appendChild(dd_bar = document.createElement("dd"));
	dl.appendChild(dd_bytes = document.createElement("dd"));
	dt.textContent = f.name;
	dd_bar.textContent = "[LOADING]";
	dd_bytes.textContent = "? / ? bytes";

	var reader = new FileReader();
	reader.onprogress = function(e) {
		var x = Math.round(20 * e.loaded / e.total);
		dd_bar.textContent = "[" + "#".repeat(x) + ".".repeat(20-x) + "]";
		dd_bytes.textContent = e.loaded + " / " + e.total + " bytes";
	};
	reader.onload = function() {
		dd_bar.textContent = "READY";
	};
	reader.onerror = function() {
		dd_bar.textContent = "ERROR";
	};
	reader.onabort = function() {
		dd_bar.textContent = "ABORTED";
	};
	reader.readAsBinaryString(f);
}
function handle(files) {
	for (var i = 0; i < files.length; ++i) {
		load(files[i]);
	}
}
</script>
<input type="file" multiple="multiple" onchange="handle(this.files)" />
<dl id="output"></dl>

”Lukeminen www-sivulle” tarkoittaa vasta tiedoston avaamista levyltä selaimen muistiin eikä suinkaan tiedoston siirtämistä palvelimelle, joten tavallaan edistymislaatikko on aika turha: pienet tiedostot aukeavat joka tapauksessa hetkessä.

ilkkak [07.09.2015 19:11:27]

#

Lukee, mutta loopissa, jossa tiedostot käsitellään, jokaiselle tiedostoon liitetään oma Filereader

Mallikoodisi ei lue kuin yhden tiedoston, vaikka olisi valittu koko leegio

function readMultipleFiles(evt) {

    var files = evt.target.files;
    if (files) {
      for (var i=0, f; f=files[i]; i++) {

        var r = new FileReader();

          r.onloadend = function(e) {...}
          r.onload = (function(f) {...}
          r.onprogress = function(e) {...}


        r.readAsDataURL(f);

      }

Ongelma on ilmeinen.

Metabolix [07.09.2015 21:12:09]

#

Mallikoodini lukee kaikki tiedostot. Lue koodi kunnolla ja kokeile edes.

Virheesi on ilmeinen: et osaa perussääntöjä siitä, miten muuttujat sidotaan nimettömiin funktioihin, ja päädyt tekemään monta identtistä funktiota, joihin on sidottu samat muuttujat (i ja f), joiden arvot muuttuvat silmukan aikana. Juuri tämän takia silmukan sisältö pitää laittaa erilliseen funktioon. Toinen vaihtoehto on lisätä FileReader-olioon omia ominaisuuksia, jotka löytyvät tapahtumankäsittelijässä this-objektista.

ilkkak [24.09.2015 11:09:16]

#

Kiva asenne! Kiitos kuitenkin. Yritetään. Tämä javascript on kyllä yksi painajainen :)

Macro [24.09.2015 20:52:02]

#

ilkkak kirjoitti:

Kiva asenne!

Tervetuloa Ohjelmointiputkaan! Asiallisemmat keskustelut Stack Overflowssa.

(Ennustus: tämä viesti tullaan poistamaan aika nopeasti :D)

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta