--- title: Usando archivos desde aplicaciones web slug: Usando_archivos_desde_aplicaciones_web tags: - Archivos - HTML5 - para_revisar - páginas_a_traducir ---
{{ gecko_minversion_header("1.9.2") }}
Al usar la API de Archivos agregada al DOM en HTML5, ahora es posible que el contenido de una página web solicite al usuario que elija un archivo local para luego leer el contenido de esos archivos. Esta selección puede hacerse tanto usando un elemento input
de HTML o arrastrando y soltando el archivo.
Seleccionar un solo archivo para usar con la API de archivo es simple:
<input type="file" id="input" onchange="handleFiles(this.files)">
Cuando el usuario selecciona un archivo, se llama a la función handleFiles()
con un objeto FileList
que contiene el objeto File
representando el archivo seleccionado por el usuario.
Si desea permitir al usuario seleccionar varios archivos, simplemente use el atributo multiple
en el elemento input
:
<input type="file" id="input" multiple="true" onchange="handleFiles(this.files)">
En este caso, la lista de archivos se pasa a la función handleFiles()contiene
un objeto
File
por cada archivo que el usuario ha seleccionado.
{{ h2_gecko_minversion("Uso de elementos ocultos del archivo de entrada usando el método click() ", "2.0") }}
Desde la versión 2.0 de Gecko {{ geckoRelease("2.0") }}, puedes esconder el elemento file {{ HTMLElement("input") }} y mostrar una interfaz propia para abrir el examinador de archivos y para mostrar que archivo o archivos ha seleccionado el usuario. Puedes hacerlo agregándole al estilo del elemento input la instrucción "display:none" y usando el método click()
en el elemento {{ HTMLElement("input") }}.
Considere este código HTML:
<input type="file" id="fileElem" multiple accept="image/*" style="display:none" onchange="handleFiles(this.files)"> <a href="#" id="fileSelect">Select some files</a>
Tu método doClick()
puede verse como esto:
var fileSelect = document.getElementById("fileSelect"), fileElem = document.getElementById("fileElem"); fileSelect.addEventListener("click", function (e) { if (fileElem) { fileElem.click(); } e.preventDefault(); // prevent navigation to "#" }, false);
Obiamente puedes darle estilo al nuevo botón para abrir el selector de archivos como desees.
Si tu campo de entrada fue creado con una librería de JavaScript como jQuery, necesitarás usar {{ domxref("element.addEventListener()") }} para agregar un manejador de eventos de cambio, como este:
var inputElement = document.getElementById("inputField"); inputElement.addEventListener("change", handleFiles, false); function handleFiles() { var fileList = this.files; /* now you can work with the file list */ }
Nota que en este caso, la función handleFiles()
busca la lista de archivos en lugar de aceptar un parámetro, ya que los detectores de eventos añadidos de esta manera no pueden aceptar un parámetro de entrada.
{{ h1_gecko_minversion("Usando Objetos URL", "2.0") }}
Gecko 2.0 {{ geckoRelease("2.0") }} introduce asistencia para el DOM {{ domxref("window.URL.createObjectURL()") }} y los métodos {{ domxref("window.URL.revokeObjectURL()") }} Esto te permite crear URLs simples para ser usadas como referencia a cualquier dato que pueda ser referenciado usando un objeto DOM File
, incluyendo archivos locales en el computador del usuario.
Cuando tienes un objeto File
te gustaría hacer referencia por URL desde HTML, puedes crear un objeto URL para que quede así :
var objectURL = window.URL.createObjectURL(fileObj);
El objeto URL es una cadena de caracteres que identifica el objeto File
. Cada vez que invocas {{ domxref("window.URL.createObjectURL()") }}, un único objeto URL es creado, incluso, si usted ya ha creado un objeto URL de ese archivo. Cada uno de estos debe ser liberado. Mientras se liberan automáticamente cuando se libera la memoria utilizada por el documento, sí tu página los usa dinámicamente, podrías liberarlos explicitamente invocando {{ domxref("window.URL.revokeObjectURL()") }}:
window.URL.revokeObjectURL(objectURL);
También puedes dejar que el usuario arrastre y suelte los archivos en la aplicación Web.
El primer paso es establecer una zona para soltar. Exactamente que parte de tu contenido aceptara soltar puede variar dependiendo de el diseño de tu aplicación, pero hacer un elemento que reciba eventos de soltar es fácil:
var dropbox; dropbox = document.getElementById("dropbox"); dropbox.addEventListener("dragenter", dragenter, false); dropbox.addEventListener("dragover", dragover, false); dropbox.addEventListener("drop", drop, false);
En este ejemplo, estamos girando el elemento con el ID "dropbox" en nuestra zona para soltar. Esto se hace mediante la adicción de manejadores que escuchen los eventos dragenter
, dragover
, y drop
.
En realidad no necesitamos hacer nada con los eventos dragenter
and dragover
en nuestro caso, por lo que estas funciones son a la vez simples. Acabar de detener la propagación del evento y evitar que la acción predeterminada ocurra:
function dragenter(e) { e.stopPropagation(); e.preventDefault(); } function dragover(e) { e.stopPropagation(); e.preventDefault(); }
La verdadera magia pasa en la función drop()
:
function drop(e) { e.stopPropagation(); e.preventDefault(); var dt = e.dataTransfer; var files = dt.files; handleFiles(files); }
Aquí, recuperamos el campo dataTransfer
del evento, a continuación tomamos la lista de archivos fuera de él, que pasa para handleFiles()
. Desde este punto, el manejo de los archivos es el mismo si el usuario utiliza el elemento de entrada o arrastrar y soltar. Obteniendo información de los archivos seleccionados.
El objeto FileList
proporcionado por el DOM de las listas de todos los archivos seleccionados por el usuario, cada una se especifica como un objeto File
. Tu puedes determinar cuantos archivos el usuario selecciona, al verificar el valor del atributo length
:
var numFiles = files.length;
Individualmente los objetos File
pueden ser recuperados simplemente accediendo a la lista como una matriz:
for (var i = 0; i < files.length; i++) { var file = files[i]; .. }
Este bucle se repite en todos los archivos de la lista de archivos.
Hay tres atributos proporcionados por el objeto File
que contienen información útil sobre el archivo.
name
size
type
Digamos que estás desarrollando el próximo gran sitio web para compartir fotos,y deseas usar HTML5 para mostrar vistas previas en miniaturas de las imágenes antes de que el usuario realmente suba los archivos. Simplemente basta con establecer el elemento de entrada o de soltar como se indicó anteriormente, y llamar una función, como la función handleFiles()
de abajo.
function handleFiles(files) { for (var i = 0; i < files.length; i++) { var file = files[i]; var imageType = /image.*/; if (!file.type.match(imageType)) { continue; } var img = document.createElement("img"); img.classList.add("obj"); img.file = file; preview.appendChild(img); var reader = new FileReader(); reader.onload = (function(aImg) { return function(e) { aImg.src = e.target.result; }; })(img); reader.readAsDataURL(file); } }
Aquí nuestro bucle maneja los archivos seleccionados por el usuario buscando en cada tipo de atributo del archivo para ver si es un archivo imagen (Buscando coincidencias con la cadena de expresión regular "image.*"). Por cada archivo de tipo imagen, creamos un nuevo elemento img. El CSS puede ser usado para crear bordes, sombras y/o especificar el tamaño de la imagen, por lo cual no es necesario hacerlo aquí.
Cada imagen tiene añadida la clase CSS "obj", para que sean fáciles de encontrar en el árbol DOM. También vamos a añadir un archivo atributo a cada imagen especificando el archivo de la imagen, o que nos permitirá buscar las imágenes para en realidad subirlas mas tarde. Por último se utilizamos {{ domxref("Node.appendChild()") }} para agregar la nueva miniatura para el área de previsualización de nuestro documento.
A continuación, se establece FileReader
para manejar de forma asincrónica la carga de la imagen y lo conecta con el elemento img.Después se crea el nuevo objeto FileReader
, hemos creado la función load
, a continuación llamamos readAsDataURL()
para empezar la operación de lectura de fondo. cuando todo el contenido del archivo de imagen se carga, se convierten en una data:
URL, cada uno se pasa por onload
callback. Nuestra implementación de esta rutina se limita a establecer el atributo src del elemento img de la imagen cargada, lo que resulta en la imagen que aparece en la miniatura en la pantalla del usuario.
{{ h1_gecko_minversion("Ejemplo: Usar URL objeto para mostrar imágenes", "2.0") }}
En este ejemplo se utiliza el objeto URL para mostrar miniaturas de las imágenes. Además, se muestra la información de otro archivo con su nonbre y tamaño. Tu puedes ver el ejemplo vivo (nota se requiere versión nocturna (nightly build) de Firefox del 22 de noviembre o posterior, o Firefox 4.0 beta 8).
Escuchar
traducción del inglés al español
El código HTML que presenta la interfaz se parece a esto:
<input type="file" id="fileElem" multiple accept="image/*" style="display:none" onchange="handleFiles(this.files)"> <a href="#" id="fileSelect">Select some files</a> <div id="fileList"> <p>¡No se han seleccionado archivos!</p> </div>
Este establece nuestro archivo {{ HTMLElement("input") }} elemento, así como un enlace que invoca el selector de archivos , ya que mantener la entrada de archivo oculto para para evitar que lo menos atractivo de la interfaz sea mostrado. Esto se explica más arriba en la sección {{ anch("Using hidden file input elements using the click() method") }}, como es el método doClick()
que invoca el selector de archivos.
El método siguiente handleFiles()
:
var fileSelect = document.getElementById("fileSelect"), fileElem = document.getElementById("fileElem"), fileList = document.getElementById("fileList"); fileSelect.addEventListener("click", function (e) { if (fileElem) { fileElem.click(); } e.preventDefault(); // evitar la navegación a "#" }, false); function handleFiles(files) { if (!files.length) { fileList.innerHTML = "<p>¡No se han seleccionado archivos!</p>"; } else { var list = document.createElement("ul"); for (var i = 0; i < files.length; i++) { var li = document.createElement("li"); list.appendChild(li); var img = document.createElement("img"); img.src = window.URL.createObjectURL(files[i]);; img.height = 60; img.onload = function () { window.URL.revokeObjectURL(this.src); } li.appendChild(img); var info = document.createElement("span"); info.innerHTML = files[i].name + ": " + files[i].size + " bytes"; li.appendChild(info); } fileList.appendChild(list); } }
Esto comienza por ir a buscar el {{ HTMLElement("div") }} con el ID "fileList". Este es el bloque en el que vamos a insertar la lista de archivos, incluyendo vistas en miniaturas.
Si el objeto {{ domxref("FileList") }} handleFiles()
es null
, se establece dentro del código HTML interno del bloque para que no aparezca "¡No se han seleccionado archivos!". De lo contrario, empezamos a contruir nuestra lista de archivos, de la siguiente manera:
Una nueva lista desordenada elemento ({{ HTMLElement("ul") }} es creada.
files
:
img.src
.Otra cosa que tu podrías querer hacer es permitir al usuario cargar un archivo o archivos seleccionados (por ejemplo, las imagenes seleccionadas con el ejemplo previo) a un servidor. Esto puede hacerse asincrónicamente muy facil.
Continuando con el código que genera las imágenes en miniatura en el ejemplo anterior, recordemos que cada imagen en la clase CSS "obj", con el correspondiente File
adjunto en el atributo de el archivo. Esto nos permite fácilmente seleccionar todas las imagenes que el usuario ha escogido para ser cargadas con {{ domxref("Document.querySelectorAll()") }}, así:
function sendFiles() { var imgs = document.querySelectorAll(".obj"); for (var i = 0; i < imgs.length; i++) { new FileUpload(imgs[i], imgs[i].file); } }
En la linea 2 se crea una matriz, llamada imgs
, de todos los elemtos in el documento con la clase CSS "obj". en nuestro caso, estas serán todas las miniaturas de las imágenes.Una vez que obtenemos esa lista, es trivial pasar por la lista, creando una nueva instancia FileUpload
para cada uno. Cada uno de estos manejadores de carga el archivo correspondiente.
La función FileUpload
acepta dos entradas: un elemento imagen y un archivo desde donde se leerán los datos de la imagen
function FileUpload(img, file) { this.ctrl = createThrobber(img); var xhr = new XMLHttpRequest(); this.xhr = xhr; var self = this; this.xhr.upload.addEventListener("progress", function(e) { if (e.lengthComputable) { var percentage = Math.round((e.loaded * 100) / e.total); self.ctrl.update(percentage); } }, false); xhr.upload.addEventListener("load", function(e){ self.ctrl.update(100); var canvas = self.ctrl.ctx.canvas; canvas.parentNode.removeChild(canvas); }, false); xhr.open("POST", "http://demos.hacks.mozilla.org/paul/demos/resources/webservices/devnull.php"); xhr.overrideMimeType('text/plain; charset=x-user-defined-binary'); xhr.sendAsBinary(file.getAsBinary()); }
La función FileUpload()
muestra arriba crear un throbber, cada uno es usado para mostrar la información de progreso, a continuación se crea un XMLHttpRequest
para manejar la carga de los datos.
Antes de transferir los datos actualmente, varios pasos preparatorios se tienen:
XMLHttpRequest
's upload "progress" listener esta configurado para actualizar la información Throbber con nuevo porcentaje, de modo que a medida que avanza la carga, el Throbber sera actualizado basado en la ultima información.XMLHttpRequest
's upload "load" manejador de evento esta configurado para actualizar como un 100% como la información de progreso (para garantizar que el indicador de progreso realmente alcanza el 100%, en caso de peculiaridades y granulidades durante el proceso). A continuación se elimina el thobber, puesto que este no es necesario. Esto hace que el Thobber desaparezca una vez que la carga esta completa.XMLHttpRequest
's open()
para empezar a generar la POST solicitud. XMLHttpRequest
function overrideMimeType()
. En este caso, estamos usando un tipo MIME genérico; puede o no ser necesario para configurar el tipo MIME para todo, dependiendo de su caso de uso.XMLHttpRequest
sendAsBinary()
es llamada para cargar el contenido de el archivo. Esto necesita ser revisado; en la actualidad esta obsoleto la rutina para extraer datos desde archivos getAsBinary() síncrona.function fileUpload(file) { // Please report improvements to: marco.buratto at tiscali.it var fileName = file.name, fileSize = file.size, fileData = file.getAsBinary(), // works on TEXT data ONLY. boundary = "xxxxxxxxx", uri = "serverLogic.php", xhr = new XMLHttpRequest(); xhr.open("POST", uri, true); xhr.setRequestHeader("Content-Type", "multipart/form-data, boundary="+boundary); // simulate a file MIME POST request. xhr.setRequestHeader("Content-Length", fileSize); xhr.onreadystatechange = function() { if (xhr.readyState == 4) { if ((xhr.status >= 200 && xhr.status <= 200) || xhr.status == 304) { if (xhr.responseText != "") { alert(xhr.responseText); // display response. } } } } var body = "--" + boundary + "\r\n"; body += "Content-Disposition: form-data; name='fileId'; filename='" + fileName + "'\r\n"; body += "Content-Type: application/octet-stream\r\n\r\n"; body += fileData + "\r\n"; body += "--" + boundary + "--"; xhr.send(body); return true; }
Esto también necesita ser modificado para trabajar con datos binarios.