File API: File Reader para Data URL y Text

En el post anterior vimos cómo acceder a la metadata de los archivos locales que el usuario insertaba en nuestro sitio, a través de la etiqueta input o bien haciendo uso de los eventos Drag and Drop.

En esta ocasión vamos a ver cómo podemos leer esos archivos desde el lado del cliente de manera asíncrona :D. Para ello haremos uso de la interfaz FileReader, la cual nos ofrece distintos mecanismos de tratamiento a través del objeto File: readAsDataURL, readAsText, readAsArrayBuffer y readAsBinaryString. En este artículo vamos a centrarnos en los dos primeros, ya que creo que es una forma realmente buena de mejorar la experiencia de usuario.

FileReader.readAsDataURL

Esta opción nos va a permitir recuperar como resultado un archivo como una URL codificada. Una forma muy simple de probar este supuesto es a través de un archivo de tipo imagen. Para ello, tenemos el siguiente ejemplo:

En esta demostración de lo que se trata es de añadir una serie de imágenes con el objetivo de obtener una vista previa de cada una de ellas. Una vez adjuntadas y generada la miniatura podemos observar que el source es el archivo codificado en base 64 directamente inyectado como fuente de la etiqueta de imagen. ¿Cómo lo hacemos?

window.onload = function() {
    //Check File API support
    if (window.File && window.FileList && window.FileReader) {
        var filesInput = document.getElementById("files");
        filesInput.addEventListener("change", function(event) {
            var files = event.target.files; //FileList object
            var output = document.getElementById("result");
            for (var i = 0; i < files.length; i++) {
                var file = files[i];
                //Only pics
                if (!file.type.match('image')) continue;
                var picReader = new FileReader();
                picReader.addEventListener("load", function(event) {
                    var picFile = event.target;
                    var div = document.createElement("div");
                    div.innerHTML = "<img class='thumbnail' src='" + picFile.result + "'" + "title='" + picFile.name + "'/>";
                    output.insertBefore(div, null);
                });
                //Read the image
                picReader.readAsDataURL(file);
            }
        });
    }
    else {
        console.log("Your browser does not support File API");
    }
}​

En este caso, para tener claro cuáles son los requisitos mínimos, he comprobado que nuestro navegador soporta window.File, window.FileList y window.FileReader ya que son las tres interfaces involucradas para este ejemplo. Exactamente igual que en post anterior controlo el cambio del input que recibe las imágenes, con el objetivo de procesar todas ellas una vez cargadas en el navegador. Gracias al objeto FileList devuelto por e.target.files podré recorrerme todos los archivos selecionados y así procesar el contenido. Dentro del bucle, comprobaré si el archivo adjuntado es una imagen, o continuaré con el siguiente. En el caso de que así sea crearé un objeto del tipo FileReader y, antes de ejecutar la lectura, me suscribiré al evento load para ser consciente de cuándo podré mostrar el resultado, en este caso, a través de una etiqueta de tipo imagen incluida dentro de un div. Una vez que tengo establecido qué voy a hacer con el resultado podré llamar a readAsDataURL.

FileReader.readAsText

En el caso de que queramos tratar texto la manera de hacerlo es igual de sencilla 😀

En este supuesto el código ha sido modificado, cambiando el comportamiento del evento load donde únicamente se inyecta el resultado en un div y, por otro lado, se utiliza readAsText en lugar de readAsDataURL.

window.onload = function() {
    //Check File API support
    if (window.File && window.FileList && window.FileReader) {
        var filesInput = document.getElementById("files");
        filesInput.addEventListener("change", function(event) {
            var files = event.target.files; //FileList object
            var output = document.getElementById("result");
            for (var i = 0; i < files.length; i++) {
                var file = files[i];
                //Only plain text
                if (!file.type.match('plain')) continue;
                var picReader = new FileReader();
                picReader.addEventListener("load", function(event) {
                    var textFile = event.target;
                    var div = document.createElement("div");
                    div.innerText = textFile.result;
                    output.insertBefore(div, null);
                });
                //Read the text file
                picReader.readAsText(file);
            }
        });
    }
    else {
        console.log("Your browser does not support File API");
    }
}​

Para comprobar el mismo podéis hacerlo adjuntando un archivo de texto plano o bien a través de este que os facilito aquí: Lore ipsum.txt 🙂

Por último, os listo cada uno de los eventos a los cuales nos podemos suscribir para su manejo:

  • loadstart: Cuando la lectura comienza.
  • progress: Mientras se está leyendo (y codificando).
  • load: La lectura ha finalizado correctamente.
  • abort: La lectura ha sido abortada. Se puede llevar a cabo llamando al método abort().
  • error: La lectura ha fallado.
  • loadend: La petición de lectura ha finalizado.

Espero que haya sido de utilidad 🙂

Demos completas:
File API – FileReader (readAsDataURL)
File API – FileReader (readAsText)

¡Saludos!