En este artículo vamos a ver cómo leer archivos que se añaden a un formulario HTML con la API File y el objeto FileReader de JavaScript, pero antes de empezar hay que dejar clara una cuestión básica.
Sólo se pueden leer archivos locales con JavaScript si el usuario ejecuta algún tipo de acción dando su conformidad, como por ejemplo, añadir los archivos a un formulario. Entonces, JavaScript nos proporciona una API File y un objeto FileReader que son los encargados de interactuar con los archivos. Al final del artículo dejo unos links para ampliar la información sobre estos objetos.
Dicho esto, es evidente que sería un atropello si cualquier web pudiera leer el disco local de un usuario. Así que vamos a centrarnos en cómo leer archivos que se añaden a un formulario HTML con la API File y el objeto FileReader.
Lo primero de todo es crear algún elemento de formulario que permita al usuario seleccionar archivos de cualquier tipo, en nuestro caso simplemente añadiremos una etiqueta <input> como por ejemplo esta:
<label>Mis archivos: <input id="myFiles" type="file" onchange="leerArchivos()" multiple /></label>
Encapsulamos el <input> dentro de la etiqueta <label> para que el clic del ratón abarque toda la extensión, esto sobretodo es útil con «inputs» tipo «checkbox» y «radio».
En cuanto al <input> en sí, lo definimos de tipo «file» y le añadimos el atributo «multiple» para poder procesar más de un archivo. También le asignamos el ID «myFiles» con el cual trabajaremos en nuestro JavaScript.
Lo más interesante en este momento es el disparador del evento «onchange
«, que ejecutará la función «leerArchivos()
«. Este es, precisamente, el tipo de conformidad del usuario que necesita el navegador para poder abrir y leer los archivos locales desde una página HTML.
Función JavaScript para leer archivos
Ahora pasemos a la función JavaScript «leerArchivos()
» que, como su nombre indica, procesará todos los archivos seleccionados por el usuario. El código es el siguiente:
// Función para leer archivos de texto
function leerArchivos() {
// Obtenemos los archivos del form y creamos un lector para cada archivo
let files = document.getElementById("myFiles").files;
for(let i=0; i<files.length; i++) {
let reader = new FileReader();
reader.fileName = files[i].name;
// Hay que crear un evento onload para mostrar el contenido una vez leído
reader.onload = function(e) {
// Mostramos los datos leídos y "filtrados" a HTML en un nuevo párrafo
let p = document.createElement("p");
document.body.appendChild(p);
p.innerHTML = "Contenido del archivo: " + e.target.fileName + "<br>" + escapeHTML(e.target.result).replaceAll("\n", "<br>");
};
// Leemos el archivo
reader.readAsText(files[i]);
}
}
Código JavaScript para leer archivos
Como se puede ver, no son muchas lineas de código, así que vamos a comentarlas paso a paso:
- let files: En esta variables obtenemos un Array con los archivos seleccionados por el usuario. Estos datos los ofrece JavaScript a través de su API File. Al vincular el <input> al ID «myFiles» podemos obtener los datos con la instrucción
document.getElementById("myFiles").files
.
Los datos obtenidos son poco importantes ahora a excepción del nombre del archivo, mediante el cual identificaremos cada archivo. Un aspecto importante es que la API File nunca nos proporcionará información sobre la ubicación/ruta del archivo por motivos de seguridad, sólo su nombre. Pero de momento con eso nos basta. - Creamos un bucle para ejecutar las funciones necesarias en cada archivo seleccionado.
- let reader: Para cada archivo creamos un objeto FileReader que se encargará de leer el contenido del archivo de forma asíncrona. Esto significa que deberemos tener un detector de eventos «onload» para cuando esté listo el archivo.
- reader.fileName: Este es un detalle importante. Al trabajar con la API File, sus objetos y eventos, aprovechamos esos objetos para añadir las propiedades que nos interesan guardar. En este caso queremos conservar el nombre del archivo proporcionado por la API File en cada objeto FileReader, así podremos recuperarlo dentro del evento «onload».
- reader.onload: Como hemos dicho, los archivos se leen de forma asíncrona y debemos crear un evento «onload» para cada archivo. Cuanto esté listo, recibiremos el contenido del archivo en la variable (e) y podremos trabajar con los datos del archivo de la siguiente forma:
- (e): Esta variable (puedes ponerle otro nombre) es un objeto devuelto por el evento «onload» que contiene diferente información sobre el archivo. Lo que nos interesa es
e.target.result
donde estará el contenido del archivo ye.target.fileName
donde estará el nombre que hemos guardado para el archivo. - En nuestro HTML añadimos un nuevo párrafo <p> a <body> para mostrar el contenido de cada archivo.
- En cada párrafo mostramos un título con el nombre del archivo guardado en el objeto FileReader.
- Seguidamente mostramos el contenido del archivo filtrado con 2 funciones: Una función propia llamada
escapeHTML()
y la función JavaScriptreplaceAll()
. Las explicaremos más adelante.
- (e): Esta variable (puedes ponerle otro nombre) es un objeto devuelto por el evento «onload» que contiene diferente información sobre el archivo. Lo que nos interesa es
- reader.readAsText(files[i]): Al crear el objeto FileReader le debemos decir el archivo que queremos leer y de qué forma lo queremos leer. En este caso lo leemos como un archivo de texto pero hay otras formas de lectura que podemos especificar simplemente cambiando esta instrucción.
Aplicar filtros
Hasta aquí, y con nuestra función «leerArchivos()
«, tendríamos bastante para mostrar el contenido de cualquier archivo de texto en una web, pero hay 2 problemas: Escapar los <tags> HTML y transformar los saltos de línea.
En una web HTML ciertos caracteres se codifican e interpretan diferente a como lo hace un editor de textos, como el bloc de notas. Para, solucionarlo vamos a ver la primera función de filtrado escapeHTML()
.
// Función para escapar entidades html
function escapeHTML(html) {
let fn = function(tag) {
let charsToReplace = {
'&' : '&',
'<' : '<',
'>' : '>',
'"' : '"'
};
return charsToReplace[tag] || tag;
}
return html.replace(/[&<>"]/g, fn);
}
Esta función la he adaptado de un código de Internet y básicamente lo que hace es recibir todo el contenido de nuestro archivo leído. Le aplica un filtro a todo el texto, donde busca los caracteres especiales (&<>»), y los sustituye por caracteres «escapados» de HTML. Es una especie de emulación a la funcion htmlspecialchars()
de PHP.
La segunda función, que es nativa de JavaScript, y que aplicamos a continuación del primer filtro es:
replaceAll("\n", "<br>")
Aquí substituimos el código de salto de línea \n que se utiliza en los editores de texto como el bloc de notas, por su equivalente <br> en HTML. Con esto conseguimos visualizar el contenido del archivo con los mismo saltos de línea.
Con esto terminaríamos nuestro artículo de hoy leer archivos con JavaScript, así que a continuación os pongo el código entero:
<!DOCTYPE html>
<head>
<title>Lector de archivos JavaScript</title>
<script>
// Función para escapar entidades html
function escapeHTML(html) {
var fn = function(tag) {
var charsToReplace = {
'&' : '&',
'<' : '<',
'>' : '>',
'"' : '"'
};
return charsToReplace[tag] || tag;
}
return html.replace(/[&<>"]/g, fn);
}
// Función para leer archivos de texto
function leerArchivos() {
// Obtenemos los archivos del form y creamos un lector para cada archivo
var files = document.getElementById("myFiles").files;
for(var i=0; i<files.length; i++) {
var reader = new FileReader();
reader.fileName = files[i].name;
// Hay que crear un evento onload para mostrar el contenido una vez leído
reader.onload = function(e) {
// Mostramos los datos leídos y "filtrados" a HTML en un nuevo párrafo
var p = document.createElement("p");
document.body.appendChild(p);
p.innerHTML = "Contenido del archivo: " + e.target.fileName + "<br>" + escapeHTML(e.target.result).replaceAll("\n", "<br>");
};
// Leemos el archivo
reader.readAsText(files[i]);
}
}
</script>
</head>
<body>
<h1>Lector JavaScript</h1>
<p>Ejemplo de lector de archivos JavaScript</p>
<label>Mis archivos: <input id="myFiles" type="file" onchange="leerArchivos()" multiple /></label>
</body>
</html>
Además de este ejemplo, se puede profundizar más con el filtrado de los datos y añadir tabulaciones \b y otros códigos internos. También se podría probar hacer diferentes tipos de lectura para archivos tipo imagen, pdf, etc.
Pero eso ya os lo dejo a vosotros 😉 jeje.
Referencias:
¡ Espero que este artículo sea de vuestro interés !