File

Esta especificación provee una API para representar archivos en aplicaciones web, además la capacidad para seleccionarlos y acceder a su contenido. Esto incluye:

La interfaz FileList: Representa un arreglo de archivos seleccionados del sistema donde se manda llamar el navegador.

Una interfaz Blob: Representa datos binarios, permite acceder a rangos de bytes dentro del objeto como un Blob distinto.

La interfaz File: Muestra atributos de un archivo como su nombre, la última fecha de modificación (en disco) del archivo, tipo de archivo.

Una interfaz de lectura de archivos FileReader: Provee métodos para leer un archivo o un objeto binario – blob – y un modelo de eventos para obtener los resultados de esas lecturas.

Un esquema de URLs para utilizar con datos binarios como archivos, para que puedan ser referenciados dentro de las aplicaciones web.

Ya que vimos de manera general los componentes de la API, vamos a ver un ejemplo de uso. Primero vamos a comenzar con un formulario y un campo de entrada para archivos.


1.El atributo multiple permite seleccionar varios archivos – Windows/Linux: CTRL + Click Mac: CMD + Click.
El nombre – archivos[] – termina con corchetes para indicar que es un arreglo.

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Archivos</title>
<style>
html {background: #f0f0f0;}
body {width: 960px; margin: 0 auto; background: #fafafa; font-family: sans-serif; font-size: 1em;}
form {padding: 2em 1em;}
</style>
</head>
<body>
	<form>
			<label for="archivo">Selecciona archivos:</label>
			<input type="file" id="archivo" name="archivos[]" multiple="multiple" />
	</form>
</body>
</html>

Vamos a verificar que el navegador sea compatible con la API. Si es así, cuando el usuario seleccione al menos un archivo o arrastre al menos un archivo al campo del formulario, se van a visualizar los datos de cada archivo en la consola.


2. Verificar que el navegador es compatible con la API

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Archivos</title>
<style>
html {background: #f0f0f0;}
body {width: 960px; margin: 0 auto; background: #fafafa; font-family: sans-serif; font-size: 1em;}
form {padding: 2em 1em;}
.hover {font-weight: bold; color: red; border: 1px solid black; background: white;}
</style>
</head>
<body>
		<form>
				<label for="archivo">Selecciona archivos:</label>
				<input type="file" id="archivo" name="archivos[]" multiple="multiple" />
		</form>
</body>

<script>
var fileselect = document.getElementById("archivo");

(function () {
  if (window.File) {
    fileselect.addEventListener("change", seleccionar_archivo, false);
  }      
}());

function seleccionar_archivo(e) {
	var archivos = e.target.files;
  for (var i = 0; i < archivos.length; i++) {        
    analizar_archivo(archivos[i]);
  }
}

function analizar_archivo(archivo) {
	console.log(archivo.name + " "  + archivo.type + " " + archivo.size);
}
</script>
</html>

Vamos a crear una sección para que el usuario suelte los archivos. En caso de que el navegador no sea compatible la vamos a quitar del DOM.


3. Vamos a crear una sección para que el usuario pueda arrastrar los archivos ahí.

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Archivos</title>
<style>
html {background: #f0f0f0;}
body {width: 960px; margin: 0 auto; background: #fafafa; font-family: sans-serif; font-size: 1em;}
form {padding: 2em 1em;}
#soltar {margin: 2em 0;}
.hover {font-weight: bold; color: white;  background: red;}
</style>
</head>
<body>
		<form>
				<label for="archivo">Selecciona archivos:</label>
				<input type="file" id="archivo" name="archivos[]" multiple="multiple" />
        <div id='soltar'>Suelta tus archivos aquí</div>        
		</form>
</body>

<script>
var fileselect = document.getElementById("archivo");
var soltar = document.getElementById("soltar");

(function () {
  if (window.File) {
    fileselect.addEventListener("change", seleccionar_archivos, false);
  	soltar.addEventListener("dragover", resaltar, false);
        soltar.addEventListener("dragleave", resaltar, false);
  	soltar.addEventListener("drop", seleccionar_archivos, false);        
  } else {
    soltar.remove();
  }      
}());
    
function resaltar(e) {
  e.preventDefault();
  if (e.type == "dragover") {
    e.target.className = 'hover';
  } else {
    e.target.className = '';
  }
}

function seleccionar_archivos(e) {
  resaltar(e);	      
	var archivos = e.target.files || e.dataTransfer.files;
  for (var i = 0; i < archivos.length; i++) {        
    analizar_archivo(archivos[i]);
  }
}

function analizar_archivo(archivo) {
	console.log(archivo.name + " "  + archivo.type + " " + archivo.size);
}
</script>
</html>

Al igual que con el ejemplo anterior, al momento de soltar los archivos en la sección definida, se deben mostrar en consola algunos datos de los archivos como nombre, tamaño, tipo.

Vamos a mostrar los datos de los archivos adjuntos como parte del documento. Los archivos que se van a procesar se pudieron obtener: seleccionando el botón «Elegir archivos», arrastrando al campo del formulario o arrastrando a la sección que definimos para que se arrastren los archivos.


4. Crear una sección para mostrar algunos datos de los archivos adjuntos.

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Archivos</title>
<style>
html {background: #f0f0f0;}
body {width: 960px; margin: 0 auto; background: #fafafa; font-family: sans-serif; font-size: 1em;}
form {padding: 2em 1em;}
#soltar {margin: 2em 0;}
.hover {font-weight: bold; color: white;  background: red;}
#visualizar_archivos {font-family: courier, monospace; font-size: 14px; width: 100%; background: #f2f2f2; color: #151515;}
</style>
</head>
<body>
		<form>
			<label for="archivo">Selecciona archivos:</label>
			<input type="file" id="archivo" name="archivos[]" multiple="multiple" />
      <div id='soltar'>Suelta tus archivos aquí</div>        
		</form>
    <h2>Archivos</h2>
    <div id='visualizar_archivos'>
      <table>
        <tr>
          <td>Nombre</td>
          <td>Tipo</td>
          <td>Tamaño</td>            
        </tr>
      </table>
    </div>
</body>

<script>
var fileselect = document.getElementById("archivo");
var soltar = document.getElementById("soltar");
var visualizar_archivos = document.getElementById('visualizar_archivos');

(function () {
  if (window.File) {
    fileselect.addEventListener("change", seleccionar_archivos, false);
  	soltar.addEventListener("dragover", resaltar, false);
        soltar.addEventListener("dragleave", resaltar, false);
  	soltar.addEventListener("drop", seleccionar_archivos, false);        
  } else {
    soltar.remove();
  }      
}());
    
function resaltar(e) {
      e.preventDefault();
  if (e.type == "dragover") {
    e.target.className = 'hover';
  } else {
    e.target.className = '';
  }
}

function seleccionar_archivos(e) {
  resaltar(e);	      
 var archivos = e.target.files || e.dataTransfer.files;
  mostrar_datos(archivos)
}

function mostrar_datos(archivos) {
  var contenido = "";
  contenido += "<table><tr><td>Nombre</td><td>Tamaño</td><td>Tamaño</td></tr>";

  for (var i = 0; i < archivos.length; i++) {        
    contenido += obtener_datos(archivos[i]);
  }
  
  contenido += "</table>";
  visualizar_archivos.innerHTML = contenido;
  
}

function obtener_datos(archivo) {
  return  "<tr><td>" + archivo.name + "</td><td>"  + archivo.type + "</td><td>" + archivo.size + "</td></tr>";
}
</script>
</html>

Hasta ahora hemos utilizado las tres primeras interfases.
Con FileList obtuvimos la lista de archivos.
Blob se utilizó de manera indirecta porque File – que se utilizamos para obtener los datos del archivo con el que estamos trabajando – hereda de Blob.
Lo que sigue es leer el contenido del archivo con FileReader.
Existen 3 modos de lectura que funcionan de manera sincrónica y asíncrona: readAsText, readAsDataURL, readAsArrayBuffer.
Vamos a utilizar los dos primeros:
readAsText para analizar archivos de texto, readAsDataURL para analizar archivos binarios (imágenes, audios, pdfs).


5. Vamos a analizar el contenido de los archivos con FileReader.

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Archivos</title>
<style>
html {background: #f0f0f0;}
body {width: 960px; margin: 0 auto; background: #fafafa; font-family: sans-serif; font-size: 1em;}
form {padding: 2em 1em;}
#soltar {margin: 2em 0;}
.hover {font-weight: bold; color: white;  background: red;}
#visualizar_archivos {font-family: courier, monospace; font-size: 14px; width: 100%; background: #f2f2f2; color: #151515;}
</style>
</head>
<body>  
	<form>
			<label for="archivo">Selecciona archivos:</label>
			<input type="file" id="archivo" name="archivos[]" multiple="multiple" />
      <div id='soltar'>Suelta tus archivos aquí</div>        
	</form>
    <h2>Archivos</h2>
    <div id='visualizar_archivos'>
      <table>
        <tr>
          <td>Nombre</td>
          <td>Tipo</td>
          <td>Tamaño</td>
          <td>Última Modificación</td>          
        </tr>
      </table>
    </div>
    <div id='contenido'></div>
</body>

<script>
    var fileselect = document.getElementById("archivo");
    var soltar = document.getElementById("soltar");
    var visualizar_archivos = document.getElementById('visualizar_archivos');
    var contenido = document.getElementById('contenido');
 
    
    (function () {
      if (window.File) {
        fileselect.addEventListener("change", seleccionar_archivos, false);
      	soltar.addEventListener("dragover", resaltar, false);
        soltar.addEventListener("dragleave", resaltar, false);
      	soltar.addEventListener("drop", seleccionar_archivos, false);        
      } else {
        soltar.remove();
      }      
    }());

    function resaltar(e) {
    	e.preventDefault();
      if (e.type == "dragover") {
        e.target.className = 'hover';
      } else {
        e.target.className = '';
      }
    }

    function seleccionar_archivos(e) {
      resaltar(e);	      
      var archivos = e.target.files || e.dataTransfer.files;      
      mostrar_datos(archivos);
    }
 
    function mostrar_datos(archivos) {
      var contenido = "";
      contenido += "<table><tr><td>Nombre</td><td>Tamaño</td><td>Tamaño</td><td>Última modificación</td></tr>";

      for (var i = 0; i < archivos.length; i++) {        
        contenido += obtener_datos(archivos[i]);
      }

      contenido += "</table>";
      visualizar_archivos.innerHTML = contenido;
      
    }

    function obtener_datos(archivo) {
      if (window.FileReader) {
        mostrar_archivo(archivo);
      }
              
      return  "<tr><td>" + archivo.name + "</td><td>"  + archivo.type + "</td><td>" + archivo.size + "</td><td>" + archivo.lastModifiedDate + "</td></tr>";
    }
    
    
    function mostrar_archivo(archivo) {
    	var reader = new FileReader();
        
    	if (archivo.type.indexOf("text") == 0) {
    		reader.onload = function(e) {
          contenido.innerHTML +=  "<p>" + archivo.name + ": <p><pre>" + e.target.result + "</pre>";
    		}
    	reader.readAsText(archivo, "utf-8"); 
        manejar_progreso(reader);
    	}  
      
    	if (archivo.type.indexOf("image") == 0) {
    		reader.onload = function(e) {
    			contenido.innerHTML +=  "<p><strong>" + archivo.name + ":</strong><br />" +  '<img src="' + e.target.result + '" /></p>';
    		}
    		reader.readAsDataURL(archivo);
        manejar_progreso(reader);
    	}
       
      // application/pdf
      if (archivo.type.indexOf("pdf") != -1) {
    		reader.onload = function(e) {
    			contenido.innerHTML +=  "<p><strong>" + archivo.name + ":</strong><br />" +  '<embed src="' + e.target.result + '"></embed></p>';
    		}
    	reader.readAsDataURL(archivo);
        manejar_progreso(reader);
      }
    
      // application/mp3
      if (archivo.type.indexOf("mp3") != -1) {
        
        var tmp_name = archivo.name;
        archivo.name = 'audio/' + tmp_name;
        
    		reader.onload = function(e) {
    			contenido.innerHTML +=  "<p><strong>" + archivo.name + ":</strong><br />" +  '<audio src="audio/' + archivo.name + '" controls="controls"></audio></p>';
    		}
    		reader.readAsDataURL(archivo);
        manejar_progreso(reader);
      }
    }

    function manejar_progreso(lector) {
      lector.onprogress = actualizar_progreso;
      lector.onerror = manejar_errores;
      
    }
    
    function actualizar_progreso(e) {
      if (e.lengthComputable) {
        var cargado = (e.loaded / e.total);
        var porcentaje = cargado * 100
        if (cargado < 1) {
          console.log("cargado: " + cargado + " = " + porcentaje.toFixed(2) + "%"); 
        }
      }
    }
    
    function manejar_errores(e) {
      if(e.target.error.name == "NotReadableError") {
        console.error("El archivo no se pudo leer");
        alert("El archivo no se pudo leer");
      }
    }

</script>
</html>

Una vez que se analizó el contenido del archivo lo podemos posicionar en el DOM.
Mientras se realiza el análisis de los documentos le podemos indicar al usuario el progreso mediante una barra donde se muestre el porcentaje realizado. Para esto podemos utilizar la API ProgressEvents.


7. Al momento de leer el o los documentos, podemos indicarle al usuario el progreso que se lleva. También es posible indicarle si existe un error durante la lectura.

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Archivos</title>
<style>
html {background: #f0f0f0;}
body {width: 960px; margin: 0 auto; background: #fafafa; font-family: sans-serif; font-size: 1em;}
form {padding: 2em 1em;}
#soltar {margin: 2em 0;}
.hover {font-weight: bold; color: white;  background: red;}
#visualizar_archivos {font-family: courier, monospace; font-size: 14px; width: 100%; background: #f2f2f2; color: #151515;}
#progress-bar {width: 500px; height: 20px; border: 1px solid #ccc; border-radius: 10px; overflow: hidden; position: relative;}
#porcentaje {width:100%; height: 100%; color: red; text-align: center; display: block; position: absolute; top: 0; left: 0; z-index: 1;}
#progress {width: 0%; height: 100%; background: #333; display: block; text-align: center;}
</style>
</head>
<body>
		<form>
		<label for="archivo">Selecciona archivos:</label>
		<input type="file" id="archivo" name="archivos[]" multiple="multiple" />
        <div id='soltar'>Suelta tus archivos aquí</div>     
        <p>Progreso:</p>
        <div id='progress-bar'>
          <div id='porcentaje'></div>
          <div id='progress'></div>
        </div>
		</form>
    <h2>Archivos</h2>
    <div id='visualizar_archivos'>
      <table>
        <tr>
          <td>Nombre</td>
          <td>Tipo</td>
          <td>Tamaño</td>
          <td>Última Modificación</td>          
        </tr>
      </table>
    </div>
    <div id='contenido'></div>
</body>

<script>
    var fileselect = document.getElementById("archivo");
    var soltar = document.getElementById("soltar");
    var visualizar_archivos = document.getElementById('visualizar_archivos');
    var contenido = document.getElementById('contenido');
    var progreso = document.getElementById('progress');
    var barra_porcentaje = document.getElementById('porcentaje');
 
    (function () {
      if (window.File) {
        fileselect.addEventListener("change", seleccionar_archivos, false);
      	soltar.addEventListener("dragover", resaltar, false);
        soltar.addEventListener("dragleave", resaltar, false);
      	soltar.addEventListener("drop", seleccionar_archivos, false);        
      } else {
        soltar.remove();
      }      
    }());
        
    function resaltar(e) {
    	e.preventDefault();
      if (e.type == "dragover") {
        e.target.className = 'hover';
      } else {
        e.target.className = '';
      }
    }

    function seleccionar_archivos(e) {
      resaltar(e);	      
     var archivos = e.target.files || e.dataTransfer.files;      
      mostrar_datos(archivos);
    }

    function mostrar_datos(archivos) {
      var contenido = "";
      contenido += "<table><tr><td>Nombre</td><td>Tamaño</td><td>Tamaño</td><td>Última modificación</td></tr>";

      for (var i = 0; i < archivos.length; i++) {        
        contenido += obtener_datos(archivos[i]);
      }

      contenido += "</table>";
      visualizar_archivos.innerHTML = contenido;
      
    }
    
    function obtener_datos(archivo) {
      if (window.FileReader) {
        mostrar_archivo(archivo);
      }
      return  "<tr><td>" + archivo.name + "</td><td>"  + archivo.type + "</td><td>" + archivo.size + "</td><td>" + archivo.lastModifiedDate + "</td></tr>";
    }
    
    function mostrar_archivo(archivo) {
    	var reader = new FileReader();

    	if (archivo.type.indexOf("text") == 0) {
    	reader.onload = function(e) {
          contenido.innerHTML +=  "<p>" + archivo.name + ": <p><pre>" + e.target.result + "</pre>";
          barra_porcentaje.textContent = "¡Listo!";
          progreso.style.width =  "100%";
    		}

    	reader.readAsText(archivo, "utf-8"); 
        manejar_progreso(reader);
    	}  
      
    	if (archivo.type.indexOf("image") == 0) {
    		reader.onload = function(e) {
    			contenido.innerHTML +=  "<p><strong>" + archivo.name + ":</strong><br />" +  '<img src="' + e.target.result + '" /></p>';
          barra_porcentaje.textContent = "¡Listo!";
          progreso.style.width =  "100%";
    		}
    	reader.readAsDataURL(archivo);
        manejar_progreso(reader);
    	}
       
      // application/pdf
      if (archivo.type.indexOf("pdf") != -1) {
    		reader.onload = function(e) {
    			contenido.innerHTML +=  "<p><strong>" + archivo.name + ":</strong><br />" +  '<embed src="' + e.target.result + '"></embed></p>';
          barra_porcentaje.textContent = "¡Listo!";
          progreso.style.width =  "100%";          
    		}
    		reader.readAsDataURL(archivo);
        manejar_progreso(reader);
      }
    
      // application/mp3
      if (archivo.type.indexOf("mp3") != -1) {        
        var tmp_name = archivo.name;
        archivo.name = 'audio/' + tmp_name;
    		reader.onload = function(e) {
// El atributo src indica que en la ubicación actual 
// del documento html existe una carpeta audio
// y ahí se encuentran los documentos.
    			contenido.innerHTML +=  "<p><strong>" + archivo.name + ":</strong><br />" +  '<audio src="audio/' + archivo.name + '" controls="controls"></audio></p>';
          barra_porcentaje.textContent = "¡Listo!";
          progreso.style.width =  "100%";          
    		}
    		reader.readAsDataURL(archivo);
        manejar_progreso(reader);
      }
    }
    
    function manejar_progreso(lector) {
      lector.onprogress = actualizar_progreso;
      lector.onerror = manejar_errores;
      
    }
    
    function actualizar_progreso(e) {
      if (e.lengthComputable) {
        // evt.loaded and evt.total are ProgressEvent properties
        var cargado = (e.loaded / e.total);
        var porcentaje = cargado * 100
        if (cargado < 1) {
          barra_porcentaje.textContent = "" + porcentaje.toFixed(2) + "%";
          progreso.style.width = porcentaje.toFixed(2) + "%"; 
        }
      }
    }
    
    function manejar_errores(e) {
      if(e.target.error.name == "NotReadableError") {
        console.error("El archivo no se pudo leer");
        alert("El archivo no se pudo leer");
      }
    }

</script>
</html>

Descarga el archivo de referencia del uso del API.