File API – Recuperando información de archivos

Desde mi punto de vista personal, creo que HTML 5 se compone de dos partes: aquellas APIs que nos abren nuevas puertas a funcionalidades que hace años ni nos planteábamos y otras que simplemente estábamos deseando que llegaran 😀 Creo que la especificación de File API la podríamos encajar en el segundo grupo :), ya que gracias a ella vamos a ser capaces de vivir mejor: Vamos a poder leer archivos desde el lado del cliente, verificar la metadata (nombre, tamaño, mimetype, fecha de modificación), controlar las subidas a servidor, etcétera.

Para ello, existen distintas interfaces:

  • File: nos facilita información del archivo: nombre, tamaño, tipo y la fecha de la última modificación.
  • FileList: se trata de un listado de múltiples objetos del tipo File, mencionado anteriormente. Este objeto se rellena con aquellos elementos seleccionados a través del input de tipo file o bien a través de un evento drop.
  • Blob: Interfaz que nos permite partir un archivo en un array de bytes.
  • FileReader: Podemos leer de manera asíncrona un archivo. Podemos controlar el progreso, errores, suscribirnos a eventos, etcétera.

En este post vamos a centrarnos en las dos primeras, File y FileList las cuales nos permitirán recuperar información de los archivos antes de enviarlos al servidor.

Recuperando la información de los archivos seleccionados

El primer punto que nos debe interesar dentro del tratamiento de archivos es la obtención de los mismos 🙂 En la gran mayoría de los sitios web seguimos haciendo uso del ya conocido input de tipo file

y, dependiendo de cuántos archivos necesitemos recuperar duplicamos dicha etiqueta N veces. Esto supone también un gran inconveniente ya que el usuario debe introducir en cada uno de los inputs el elemento indicado y, como todos sabemos, la mayor parte de la veces incluso ni los desarrolladores nos paramos a leer qué es lo que realmente se nos está pidiendo 🙂 Podemos seguir haciendo uso de esta etiqueta pero teniendo en cuenta la siguiente mejora: el atributo multiple. Gracias a él seremos capaces de seleccionar más de un archivo a través del cuadro de diálogo y, una vez seleccionado, tratar los mismos y decidir si tenemos todo lo que necesitamos para procesar la petición.


Una vez que ya hemos elegido si queremos un comportamiento múltiple o no, el siguiente paso es controlar el evento change de nuestro control input, de tal forma que podamos interceptar cuándo ha sufrido modificaciones (se han seleccionado archivos, se han modificado los que estaban seleccionados, etcétera). Dentro de ese evento, podremos recuperar el objeto FileList, el cual contendrá tantos archivos como hayamos seleccionado a través del cuadro de diálogo con la metadata correspondiente por cada uno de ellos:

window.onload = function() {

    //Check File API support
    if (window.File && window.FileList) {
        var filesInput = document.getElementById("files");

        filesInput.addEventListener("change", function(event) {

            var files = event.target.files; //It returns a FileList object
            var filesInfo = "";

            for (var i = 0; i < files.length; i++) {
                var file = files[i];

                filesInfo += "<li>Name: " + file.name + "</br>" + " Size: " + file.size + " bytes</br>" + " Type: " + file.type + "</br>" + " Modified Date: " + file.lastModifiedDate + "</li>";

            }

            var output = document.getElementById("result");

            output.innerHTML = "<ul>" + filesInfo + "</ul>";

        });
    }
    else {
        console.log("Your browser does not support File API");
    }
}​

Como podemos ver en el ejemplo anterior, una vez que se lanza el evento change podemos recuperar el listado de objetos de nuestro control a través de event.target.files, consiguiendo de esta manera el objeto FileList. Una vez obtenido el mismo, recorremos cada uno de los elementos de tipo File y recuperamos las propiedades name, size, type y lastModifiedDate para posteriormente mostrarlas al usuario. Podemos ver el resultado de dicho ejemplo en la pestaña result:

Otra alternativa al uso de input es el manejo de los eventos Drag and Drop, el cual ya empieza a estar muy de moda 🙂 Lo cierto es que no es nada complicado su uso y no es necesario depender de ninguna librería de terceros.

En este ejemplo, basta con arrastrar elementos dentro del recuadro y obtendremos la información de cada uno de ellos. ¿Cómo lo hacemos?

function dragHandler(event) {
    event.stopPropagation();
    event.preventDefault();

    var drop_area = document.getElementById("drop_area");
    drop_area.className = "area drag";
}

function filesDroped(event) {
    event.stopPropagation();
    event.preventDefault();

    drop_area.className = "area";

    var files = event.dataTransfer.files; //It returns a FileList object
    var filesInfo = "";

    for (var i = 0; i < files.length; i++) {
        var file = files[i];

        filesInfo += "<li>Name: " + file.name + "</br>" + " Size: " + file.size + " bytes</br>" + " Type: " + file.type + "</br>" + " Modified Date: " + file.lastModifiedDate + "</li>";

    }

    var output = document.getElementById("result");

    output.innerHTML = "<ul>" + filesInfo + "</ul>";
}

window.onload = function() {

    //Check File API support
    if (window.File && window.FileList) {
        var drop_area = document.getElementById("drop_area");

        drop_area.addEventListener("dragover", dragHandler);
        drop_area.addEventListener("drop", filesDroped);

    }
    else {
        console.log("Your browser does not support File API");
    }
}​

Nota: En Internet Explorer no está comportándose correctamente.

Como podemos ver en el ejemplo anterior, hemos creado dos funciones para manejar los eventos dragover y drop. El primero de ellos se ejecutará en el momento que hayamos seleccionado archivos locales y, sin soltarlos, nos movemos con el cursor sobre el navegador. En este ejemplo solamente he modificado las clases que alteran el estilo del div drop_area, además de anular los comportamientos por defecto del navegador (abrir un archivo, mostrar una imagen, etcétera). El segundo evento se lanza cuando dichos archivos han sido soltados dentro del espacio permitido. En ese momento podremos recuperar la información de todos los archivos que se arrastraron hasta la zona. Del mismo modo, será necesario anular los comportamientos por defecto.

Espero que haya sido de utilidad 😀

Demos completas:
File API
File API – Drag and Drop

¡Saludos!