mozilla

Revision 98065 of Usando archivos desde aplicaciones web

  • Enlace amigable (slug) de la revisión: Usando_archivos_desde_aplicaciones_web
  • Título de la revisión: Usando archivos desde aplicaciones web
  • Id de la revisión: 98065
  • Creada:
  • Creador: maedca
  • ¿Es la revisión actual? No
  • Comentario no changes

Contenido de la revisión

{{ Traducción("inglés", "using_files_from_web_applications", "en") }}

{{ 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 lugar 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 archivos usando HTML

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 elige un archivo, se llama a la función handleFiles() con un objeto FileList que contiene el objeto File representando al archivo seleccionado por el usuario.

Si desea permitir a el usuario seleccionar varios archivos, sólo tiene que usar el atributo multiple  en el elemento de entrada:

<input type="file" id="input" multiple="true" onchange="handleFiles(this.files)">

En este caso, la lista de archivos se pasa al handleFiles() función contiene un Archivo objeto por cada archivo que el usuario ha seleccionado.

{{ h2_gecko_minversion("Using hidden file input elements using the click() method", "2.0") }}

Starting in Gecko 2.0 {{ geckoRelease("2.0") }}, you can hide the admittedly ugly file {{ HTMLElement("input") }} element and present your own interface for opening the file picker and displaying which file or files the user has selected. You can do this by styling the input element with "display:none" and calling the click() method on the {{ HTMLElement("input") }} element.

Considere este código HTML:

<form>
  <input type="file" id="fileElem" multiple accept="image/*" style="display:none" onchange="handleFiles(this.files)">
</form>

<a href="javascript:doClick()">Select some files</a> 

Tu metodo doClick() puede verse como este:

function doClick() {
  var el = document.getElementById("fileElem");
  if (el) {
    el.click();
  }
}

Obviamente puedes darle estilo a  el nuevo botón para abrir el selector de archivos como desee.

Dinámica de la adición de un detector de cambio

Si tu campo de entrada fue creado con una libreria de JavaScript como jQuery, necesitara usar {{ domxref("element.addEventListener()") }} para agregar el 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 */
}

Note 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("Using blob URLs", "2.0") }}

Gecko 2.0 {{ geckoRelease("2.0") }} introduces support for the DOM {{ domxref("window.createBlobURL()") }} and {{ domxref("window.revokeBlobURL()") }} methods. These let you create simple URL strings that can be used to reference any data that can be referred to using a DOM File object, including local files on the user's computer.

Cuando tu tienes un Archivo objeto te gustaría hacer referencia por URL desde HTML, puedes crear una URL burbuja para que quede así:

var blobURL = window.createBlobURL(fileObj);

La burbuja URL es una cadena que identifica el objeto Archivo. Cada vez que llamas {{ domxref("window.createBlobURL()") }}, una unica burbuja URL es creada. Cada una de estas debe ser liberada. Mientras se liberan automáticamente cuando el documento se descarga, si tu página los usa de forma dinámica, debes liberarlos explícitamente llamando {{ domxref("window.revokeBlobURL()") }}:

window.revokeBlobURL(blobURL);

Selección de archivos usando arrastrar y soltar

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 escuchas para el dragenter, dragover, y drop events.

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. Acaban 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 tire de la lista de archivos fuera de este, pasando al handleFiles(). A partir de ahora , el manejo de archivos es lo mismo si el usuario utiliza el elemento entrada o arrastrar y soltar.

Obteniendo información de los archivos seleccionados

El objeto ArchivoLista proporcionado por el DOM de las listas de todos los archivos seleccionados por el usuario, cada una se especifica como un objeto Archivo. Tu puedes determinar cuantos archivos el usuario selecciona, al verificar el valor del atributo longitud:

var numFiles = files.length;

Individual objetos Archivo 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 Archivo que contienen información útil sobre el archivo.

nombre
El nombre de archivo como cadena de sólo lectura. Esto es sólo el nombre de el archivo y no incluye ninguna información de la ruta.
tamaño
El tamaño del  archivo en bytes como de solo lectura entero de 64 bits.
tipo
El tipo MIME de el archivo como una cadena de sólo lectura, o "" si el tipo no puede ser determinado.

Ejemplo: Mostrando miniaturas de las imágenes seleccionadas por el usuario

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 manejador de los archivos seleccionado por el usuario mira el atributo tipo de cada archivo para ver si es un archivo de imagen (haciendo una coincidencia de expresión regular en la cadena "imagen.*"). Para cada archivo que es una imagen, creamos un nuevo elemento img. CSS puede ser usado para establecer cualquier borde bonito, sombras, y para especificar el tamaño de la imagen, de modo que ni siquiera hay que hacer aquí.

Cada imagen tiene la clase CSS "obj", añadida a la misma, para que sean fáciles de encontrar en el árbol DOM. Tambien 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.

Then we establish the FileReader to handle actually asynchronously loading the image and attaching it to the img element. After creating the new FileReader object, we set up its onload function, then call readAsDataURL() to start the read operation in the background. When the entire contents of the image file are loaded, they are converted into a data: URL, which is passed to the onload callback. Our implementation of this routine simply sets the img element's src attribute to the loaded image, which results in the image appearing in the thumbnail on the user's screen.

{{ h1_gecko_minversion("Example: Using blob URLs to display images", "2.0") }}

This example uses blob URLs to display image thumbnails. In addition, it displays other file information including their names and sizes. You can view the example live (note that it requires a nightly build of Firefox from September 23 or later, or Firefox 4.0 beta 7).

The HTML that presents the interface looks like this:

<form>
  <input type="file" id="fileElem" multiple accept="image/*" style="display:none" onchange="handleFiles(this.files)">
</form>
<a href="javascript:doClick()">Select some files</a>
<div id="fileList">
  <p>No files selected!</p>
</div>

This establishes our file {{ HTMLElement("input") }} element, as well as a link that invokes the file picker, since we keep the file input hidden to prevent that less-than-attractive UI from being displayed. This is explained above in the section {{ anch("Using hidden file input elements using the click() method") }}, as is the doClick() method that invokes the file picker.

The handleFiles() method follows:

function handleFiles(files) {
  var d = document.getElementById("fileList");
  if (!files.length) {
    d.innerHTML = "<p>No files selected!</p>";
  } else {
    var list = document.createElement("ul");
    d.appendChild(list);
    for (var i=0; i < files.length; i++) {
      var li = document.createElement("li");
      list.appendChild(li);
      
      var img = document.createElement("img");
      img.src = window.createBlobURL(files[i]);;
      img.height = 60;
      img.onload = function() {
        window.revokeBlobURL(this.src);
      }
      li.appendChild(img);
      
      var info = document.createElement("span");
      info.innerHTML = files[i].name + ": " + files[i].size + " bytes";
      li.appendChild(info);
    }
  }
}

This starts by fetching the URL of the {{ HTMLElement("div") }} with the ID "fileList". This is the block into which we'll insert out file list, including thumbmails.

If the {{ domxref("FileList") }} object passed to handleFiles() is null, we simply set the inner HTML of the block to display "No files selected!". Otherwise, we start building our file list, as follows:

  1. A new unordered list ({{ HTMLElement("ul") }} element is created.
  2. The new list element is inserted into the {{ HTMLElement("div") }} block by calling its {{ domxref("element.appendChild()") }} method.
  3. For each {{ domxref("File") }} in the {{ domxref("FileList") }} represented by files:
    1. Create a new list item ({{ HTMLElement("li") }}) element and insert it into the list.
    2. Create a new image ({{ HTMLElement("img") }}) element.
    3. Set the image's source to a new blob URL representing the file, using {{ domxref("window.createBlobURL()") }} to create the blob URL.
    4. Set the image's height to 60 pixels.
    5. Set up the image's load event handler to release the blob URL, since it's no longer needed once the image has been loaded. This is done by calling the {{ domxref("window.revokeBlobURL()") }} method, passing in the blob URL string as specified by img.src.
    6. Append the new list item to the list.

Example: Uploading a user-selected file

Another thing you might want to do is let the user upload the selected file or files (such as the images selected using the previous example) to a server. This can be done asynchronously very easily.

Creating the upload tasks

Continuing with the code that builds the thumbnails in the previous example, recall that every thumbnail image is in the CSS class "obj", with the corresponding File attached in a file attribute. This lets us very easily select all the images the user has chosen for uploading using {{ domxref("Document.querySelectorAll()") }}, like this:

function sendFiles() {
  var imgs = document.querySelectorAll(".obj");
  
  for (var i = 0; i < imgs.length; i++) {
    new FileUpload(imgs[i], imgs[i].file);
  }
}

Line 2 creates an array, called imgs, of all the elements in the document with the CSS class "obj". In our case, these will be all the image thumbnails. Once we have that list, it's trivial to go through the list, creating a new FileUpload instance for each. Each of these handles uploading the corresponding file.

Handling the upload process for a file

The FileUpload function accepts two inputs: an image element and a file from which to read the image data.

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());
}

The FileUpload() function shown above creates a throbber, which is used to display progress information, then creates an XMLHttpRequest to handle uploading the data.

Before actually transferring the data, several preparatory steps are taken:

  1. The XMLHttpRequest's upload "progress" listener is set to update the throbber with new percentage information, so that as the upload progresses, the throbber will be updated based on the latest information.
  2. The XMLHttpRequest's upload "load" event handler is set to update the throbber with 100% as the progress information (to ensure the progress indicator actually reaches 100%, in case of granularity quirks during the process). It then removes the throbber, since it's no longer needed. This causes the throbber to disappear once the upload is complete.
  3. The request to upload the image file is opened by calling XMLHttpRequest's open() method to start generating a POST request.
  4. The MIME type for the upload is set by calling the XMLHttpRequest function overrideMimeType(). In this case, we're using a generic MIME type; you may or may not need to set the MIME type at all, depending on your use case.
  5. Finally, the XMLHttpRequest function sendAsBinary() is called to upload the file's content. This needs to be revised; currently using the deprecated synchronous getAsBinary() routine to pull the data from the file.

Handling the upload process for a file, asynchronously

function fileUpload(file) {
  // Please report improvements to: marco.buratto at tiscali.it
  
  var fileName = file.name;
  var fileSize = file.size;
  var fileData = file.getAsBinary(); // works on TEXT data ONLY.
          
  var boundary = "xxxxxxxxx";
  var uri = "serverLogic.php";   
  
  var 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;
}

This needs to be modified for working with binary data, too.

See also

{{ HTML5ArticleTOC() }}

Fuente de la revisión

<p>{{ Traducción("inglés", "using_files_from_web_applications", "en") }}</p>
<p>{{ gecko_minversion_header("1.9.2") }}</p>
<p>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 lugar leer el contenido de esos archivos. Esta selección puede hacerse tanto usando un elemento <a href="/en/DOM/HTMLInputElement" title="en/DOM/Input"><code>input</code></a> de HTML o arrastrando y soltando el archivo.</p>
<h2>Seleccionar archivos usando HTML</h2>
<p>Seleccionar un solo archivo para usar con la API de archivo es simple:</p>
<pre><code>&lt;input type="file" id="input" onchange="handleFiles(this.files)"&gt;</code>
</pre>
<p>Cuando el usuario elige un archivo, se llama a la función <code>handleFiles()</code> con un objeto <a href="/en/DOM/FileList" title="en/DOM/FileList"><code>FileList</code></a> que contiene el objeto <a href="/en/DOM/File" title="en/DOM/File"><code>File</code></a> representando al archivo seleccionado por el usuario.</p>
<p>Si desea permitir a el usuario seleccionar varios archivos, sólo tiene que usar <code>el atributo multiple</code>  en el elemento de entrada:</p>
<p><code>&lt;input type="file" id="input" multiple="true" onchange="handleFiles(this.files)"&gt;</code></p>
<p>En este caso, la lista de archivos se pasa al <code>handleFiles()</code> función contiene un <a href="/en/DOM/File" title="en/DOM/File"><code>Archivo</code></a> objeto por cada archivo que el usuario ha seleccionado.</p>
<p>{{ h2_gecko_minversion("Using hidden file input elements using the click() method", "2.0") }}</p>
<p>Starting in Gecko 2.0 {{ geckoRelease("2.0") }}, you can hide the admittedly ugly file {{ HTMLElement("input") }} element and present your own interface for opening the file picker and displaying which file or files the user has selected. You can do this by styling the input element with "display:none" and calling the <code>click()</code> method on the {{ HTMLElement("input") }} element.</p>
<p>Considere este código HTML:</p>
<pre class="deki-transform">&lt;form&gt;
  &lt;input type="file" id="fileElem" multiple accept="image/*" style="display:none" onchange="handleFiles(this.files)"&gt;
&lt;/form&gt;

&lt;a href="javascript:doClick()"&gt;Select some files&lt;/a&gt; 
</pre>
<p>Tu metodo <code>doClick()</code> puede verse como este:</p>
<pre class="deki-transform">function doClick() {
  var el = document.getElementById("fileElem");
  if (el) {
    el.click();
  }
}
</pre>
<p>Obviamente puedes darle estilo a  el nuevo botón para abrir el selector de archivos como desee.</p>
<h3><span class="short_text" id="result_box" lang="es"><span class="hps" title="Haz clic para obtener traducciones alternativas">Dinámica de</span> <span class="hps" title="Haz clic para obtener traducciones alternativas">la adición de</span> <span class="hps" title="Haz clic para obtener traducciones alternativas">un</span> <span class="hps" title="Haz clic para obtener traducciones alternativas">detector de</span> <span class="hps" title="Haz clic para obtener traducciones alternativas">cambio</span></span></h3>
<p>Si tu campo de entrada fue creado con una libreria de JavaScript como <a class=" external" href="http://www.jquery.com/" title="http://www.jquery.com/">jQuery</a>, necesitara usar {{ domxref("element.addEventListener()") }} para agregar el manejador de eventos de cambio, como este:</p>
<pre class="deki-transform">var inputElement = document.getElementById("inputField");
inputElement.addEventListener("change", handleFiles, false);

function handleFiles() {
  var fileList = this.files;

  /* now you can work with the file list */
}
</pre>
<p>Note que en este caso, la función <code>handleFiles()</code> 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.</p>
<p>{{ h1_gecko_minversion("Using blob URLs", "2.0") }}</p>
<p>Gecko 2.0 {{ geckoRelease("2.0") }} introduces support for the DOM {{ domxref("window.createBlobURL()") }} and {{ domxref("window.revokeBlobURL()") }} methods. These let you create simple URL strings that can be used to reference any data that can be referred to using a DOM <a href="/en/DOM/File" title="en/DOM/File"><code>File</code></a> object, including local files on the user's computer.</p>
<p>Cuando tu tienes un <a href="/en/DOM/File" title="en/DOM/File"><code>Archivo</code></a> objeto te gustaría hacer referencia por URL desde HTML, puedes crear una URL burbuja para que quede así:</p>
<pre>var blobURL = window.createBlobURL(fileObj);
</pre>
<p>La burbuja URL es una cadena que identifica el objeto <a href="/en/DOM/File" title="en/DOM/File"><code>Archivo</code></a>. Cada vez que llamas {{ domxref("window.createBlobURL()") }}, una unica burbuja URL es creada. Cada una de estas debe ser liberada. <span id="result_box" lang="es"><span class="hps" title="Haz clic para obtener traducciones alternativas">Mientras</span> <span class="hps" title="Haz clic para obtener traducciones alternativas">se liberan</span> <span class="hps" title="Haz clic para obtener traducciones alternativas">automáticamente</span> <span class="hps" title="Haz clic para obtener traducciones alternativas">cuando el documento</span> <span class="hps" title="Haz clic para obtener traducciones alternativas">se</span> <span class="hps" title="Haz clic para obtener traducciones alternativas">descarga</span></span>, si tu página los usa de forma dinámica, debes liberarlos explícitamente llamando {{ domxref("window.revokeBlobURL()") }}:</p>
<pre>window.revokeBlobURL(blobURL);
</pre>
<h2>Selección de archivos usando arrastrar y soltar</h2>
<p><span id="result_box" lang="es"><span class="hps" title="Haz clic para obtener traducciones alternativas">También</span> <span class="hps" title="Haz clic para obtener traducciones alternativas">puedes dejar que</span> <span class="hps" title="Haz clic para obtener traducciones alternativas">el</span> <span class="hps" title="Haz clic para obtener traducciones alternativas">usuario</span> <span class="hps" title="Haz clic para obtener traducciones alternativas">arrastre</span> <span class="hps" title="Haz clic para obtener traducciones alternativas">y</span> <span class="hps" title="Haz clic para obtener traducciones alternativas">suelte los archivos en</span> <span class="hps" title="Haz clic para obtener traducciones alternativas">la</span> <span class="hps" title="Haz clic para obtener traducciones alternativas">aplicación</span> <span class="hps" title="Haz clic para obtener traducciones alternativas">Web</span></span>.</p>
<p>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:</p>
<pre class="deki-transform">var dropbox;

dropbox = document.getElementById("dropbox");
dropbox.addEventListener("dragenter", dragenter, false);
dropbox.addEventListener("dragover", dragover, false);
dropbox.addEventListener("drop", drop, false);
</pre>
<p>En este ejemplo, estamos girando el elemento con el ID "dropbox" en nuestra zona para soltar. Esto se hace mediante la adicción de escuchas para el <code>dragenter</code>, <code>dragover</code>, y <code>drop</code> events.</p>
<p>En realidad no necesitamos hacer nada con los eventos <code>dragenter</code> and <code>dragover</code> en nuestro caso, por lo que estas funciones son a la vez simples. Acaban de detener la propagación del evento y evitar que la acción predeterminada ocurra:</p>
<pre class="deki-transform">function dragenter(e) {
  e.stopPropagation();
  e.preventDefault();
}

function dragover(e) {
  e.stopPropagation();
  e.preventDefault();
} 
</pre>
<p>La verdadera magia pasa en la función <code>drop()</code>:</p>
<pre class="deki-transform">function drop(e) {
  e.stopPropagation();
  e.preventDefault();

  var dt = e.dataTransfer;
  var files = dt.files;

  handleFiles(files);
}
</pre>
<p>Aquí, recuperamos el campo <code>dataTransfer</code> del evento, a continuación tire de la lista de archivos fuera de este, pasando al <code>handleFiles()</code>. A partir de ahora , el manejo de archivos es lo mismo si el usuario utiliza el elemento <code>entrada</code> o arrastrar y soltar.</p>
<h2>Obteniendo información de los archivos seleccionados</h2>
<p>El objeto <a href="/en/DOM/FileList" title="en/DOM/FileList"><code>ArchivoLista</code></a> proporcionado por el DOM de las listas de todos los archivos seleccionados por el usuario, cada una se especifica como un objeto <a href="/en/DOM/File" title="en/DOM/File"><code>Archivo</code></a>. Tu puedes determinar cuantos archivos el usuario selecciona, al verificar el valor del atributo <code>longitud</code>:</p>
<pre>var numFiles = files.length;
</pre>
<p>Individual objetos <a href="/en/DOM/File" title="en/DOM/File"><code>Archivo</code></a> pueden ser recuperados simplemente accediendo a la lista como una matriz:</p>
<pre class="deki-transform">for (var i = 0; i &lt; files.length; i++) {
  var file = files[i];
  ..
}
</pre>
<p>Este bucle se repite en todos los archivos de la lista de archivos.</p>
<p>Hay tres atributos proporcionados por el objeto <a href="/en/DOM/File" title="en/DOM/File"><code>Archivo</code></a> que contienen información útil sobre el archivo.</p>
<dl> <dt><code>nombre</code></dt> <dd>El nombre de archivo como cadena de sólo lectura. Esto es sólo el nombre de el archivo y no incluye ninguna información de la ruta.</dd> <dt><code>tamaño</code></dt> <dd>El tamaño del  archivo en bytes como de solo lectura entero de 64 bits.</dd> <dt><code>tipo</code></dt> <dd>El tipo MIME de el archivo como una cadena de sólo lectura, o "" si el tipo no puede ser determinado.</dd>
</dl>
<h2>Ejemplo: Mostrando miniaturas de las imágenes seleccionadas por el usuario</h2>
<p>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 <code>handleFiles()</code> de abajo.</p>
<pre class="deki-transform">function handleFiles(files) {
  for (var i = 0; i &lt; 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);
  }
}
</pre>
<p>Aquí nuestro bucle manejador de los archivos seleccionado por el usuario mira el atributo tipo de cada archivo para ver si es un archivo de imagen (haciendo una coincidencia de expresión regular en la cadena "imagen.*"). Para cada archivo que es una imagen, creamos un nuevo elemento img. CSS puede ser usado para establecer cualquier borde bonito, sombras, y para especificar el tamaño de la imagen, de modo que ni siquiera hay que hacer aquí.</p>
<p>Cada imagen tiene la clase CSS "obj", añadida a la misma, para que sean fáciles de encontrar en el árbol DOM. Tambien vamos a añadir un <code>archivo</code> 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.</p>
<p>Then we establish the <a href="/en/DOM/FileReader" title="en/DOM/FileReader"><code>FileReader</code></a> to handle actually asynchronously loading the image and attaching it to the <code>img</code> element. After creating the new <code>FileReader</code> object, we set up its <code>onload</code> function, then call <code>readAsDataURL()</code> to start the read operation in the background. When the entire contents of the image file are loaded, they are converted into a <code>data:</code> URL, which is passed to the <code>onload</code> callback. Our implementation of this routine simply sets the <code>img</code> element's <code>src</code> attribute to the loaded image, which results in the image appearing in the thumbnail on the user's screen.</p>
<p>{{ h1_gecko_minversion("Example: Using blob URLs to display images", "2.0") }}</p>
<p>This example uses blob URLs to display image thumbnails. In addition, it displays other file information including their names and sizes. You can <a href="/samples/domref/file-click-demo.html" title="https://developer.mozilla.org/samples/domref/file-click-demo.html">view the example live</a> (note that it requires a <a class=" external" href="http://nightly.mozilla.org/" title="http://nightly.mozilla.org/">nightly build</a> of Firefox from September 23 or later, or Firefox 4.0 beta 7).</p>
<p>The HTML that presents the interface looks like this:</p>
<pre class="deki-transform">&lt;form&gt;
  &lt;input type="file" id="fileElem" multiple accept="image/*" style="display:none" onchange="handleFiles(this.files)"&gt;
&lt;/form&gt;
&lt;a href="javascript:doClick()"&gt;Select some files&lt;/a&gt;
&lt;div id="fileList"&gt;
  &lt;p&gt;No files selected!&lt;/p&gt;
&lt;/div&gt;
</pre>
<p>This establishes our file {{ HTMLElement("input") }} element, as well as a link that invokes the file picker, since we keep the file input hidden to prevent that less-than-attractive UI from being displayed. This is explained above in the section {{ anch("Using hidden file input elements using the click() method") }}, as is the <code>doClick()</code> method that invokes the file picker.</p>
<p>The <code>handleFiles()</code> method follows:</p>
<pre class="deki-transform">function handleFiles(files) {
  var d = document.getElementById("fileList");
  if (!files.length) {
    d.innerHTML = "&lt;p&gt;No files selected!&lt;/p&gt;";
  } else {
    var list = document.createElement("ul");
    d.appendChild(list);
    for (var i=0; i &lt; files.length; i++) {
      var li = document.createElement("li");
      list.appendChild(li);
      
      var img = document.createElement("img");
      img.src = window.createBlobURL(files[i]);;
      img.height = 60;
      img.onload = function() {
        window.revokeBlobURL(this.src);
      }
      li.appendChild(img);
      
      var info = document.createElement("span");
      info.innerHTML = files[i].name + ": " + files[i].size + " bytes";
      li.appendChild(info);
    }
  }
}
</pre>
<p>This starts by fetching the URL of the {{ HTMLElement("div") }} with the ID "fileList". This is the block into which we'll insert out file list, including thumbmails.</p>
<p>If the {{ domxref("FileList") }} object passed to <code>handleFiles()</code> is <code>null</code>, we simply set the inner HTML of the block to display "No files selected!". Otherwise, we start building our file list, as follows:</p>
<ol> <li>A new unordered list ({{ HTMLElement("ul") }} element is created.</li> <li>The new list element is inserted into the {{ HTMLElement("div") }} block by calling its {{ domxref("element.appendChild()") }} method.</li> <li>For each {{ domxref("File") }} in the {{ domxref("FileList") }} represented by <code>files</code>: <ol> <li>Create a new list item ({{ HTMLElement("li") }}) element and insert it into the list.</li> <li>Create a new image ({{ HTMLElement("img") }}) element.</li> <li>Set the image's source to a new blob URL representing the file, using {{ domxref("window.createBlobURL()") }} to create the blob URL.</li> <li>Set the image's height to 60 pixels.</li> <li>Set up the image's load event handler to release the blob URL, since it's no longer needed once the image has been loaded. This is done by calling the {{ domxref("window.revokeBlobURL()") }} method, passing in the blob URL string as specified by <code>img.src</code>.</li> <li>Append the new list item to the list.</li> </ol> </li>
</ol>
<h2>Example: Uploading a user-selected file</h2>
<p>Another thing you might want to do is let the user upload the selected file or files (such as the images selected using the previous example) to a server. This can be done asynchronously very easily.</p>
<h3>Creating the upload tasks</h3>
<p>Continuing with the code that builds the thumbnails in the previous example, recall that every thumbnail image is in the CSS class "obj", with the corresponding <a href="/en/DOM/File" title="en/DOM/File"><code>File</code></a> attached in a <code>file</code> attribute. This lets us very easily select all the images the user has chosen for uploading using {{ domxref("Document.querySelectorAll()") }}, like this:</p>
<pre class="deki-transform">function sendFiles() {
  var imgs = document.querySelectorAll(".obj");
  
  for (var i = 0; i &lt; imgs.length; i++) {
    new FileUpload(imgs[i], imgs[i].file);
  }
}
</pre>
<p>Line 2 creates an array, called <code>imgs</code>, of all the elements in the document with the CSS class "obj". In our case, these will be all the image thumbnails. Once we have that list, it's trivial to go through the list, creating a new <code>FileUpload</code> instance for each. Each of these handles uploading the corresponding file.</p>
<h3>Handling the upload process for a file</h3>
<p>The <code>FileUpload</code> function accepts two inputs: an image element and a file from which to read the image data.</p>
<pre class="deki-transform">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());
}
</pre>
<p>The <code>FileUpload()</code> function shown above creates a throbber, which is used to display progress information, then creates an <a href="/en/XMLHttpRequest" title="en/XMLHttpRequest"><code>XMLHttpRequest</code></a> to handle uploading the data.</p>
<p>Before actually transferring the data, several preparatory steps are taken:</p>
<ol> <li>The <code>XMLHttpRequest</code>'s upload "progress" listener is set to update the throbber with new percentage information, so that as the upload progresses, the throbber will be updated based on the latest information.</li> <li>The <code>XMLHttpRequest</code>'s upload "load" event handler is set to update the throbber with 100% as the progress information (to ensure the progress indicator actually reaches 100%, in case of granularity quirks during the process). It then removes the throbber, since it's no longer needed. This causes the throbber to disappear once the upload is complete.</li> <li>The request to upload the image file is opened by calling <code>XMLHttpRequest</code>'s <code>open()</code> method to start generating a POST request.</li> <li>The MIME type for the upload is set by calling the <code>XMLHttpRequest</code> function <code>overrideMimeType()</code>. In this case, we're using a generic MIME type; you may or may not need to set the MIME type at all, depending on your use case.</li> <li>Finally, the <code>XMLHttpRequest</code> function <code>sendAsBinary()</code> is called to upload the file's content. <em>This needs to be revised; currently using the deprecated synchronous getAsBinary() routine to pull the data from the file.</em></li>
</ol>
<h3>Handling the upload process for a file, asynchronously</h3>
<pre class="deki-transform">function fileUpload(file) {
  // Please report improvements to: marco.buratto at tiscali.it
  
  var fileName = file.name;
  var fileSize = file.size;
  var fileData = file.getAsBinary(); // works on TEXT data ONLY.
          
  var boundary = "xxxxxxxxx";
  var uri = "serverLogic.php";   
  
  var 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 &gt;= 200 &amp;&amp; xhr.status &lt;= 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;
}
</pre>
<p><em>This needs to be modified for working with binary data, too.<br>
</em></p>
<h2>See also</h2>
<ul> <li><code><a href="/en/DOM/File" title="en/DOM/File">File</a><br> </code></li> <li><code><a href="/en/DOM/FileList" title="en/DOM/FileList">FileList</a><br> </code></li> <li><a href="/en/DOM/FileReader" title="en/DOM/FileReader"><code>FileReader</code></a></li> <li><a href="/En/XMLHttpRequest/Using_XMLHttpRequest" title="En/Using XMLHttpRequest">Using XMLHttpRequest</a></li> <li><a href="/en/XMLHttpRequest" title="en/XMLHttpRequest"><code>XMLHttpRequest</code></a></li>
</ul>
<p>{{ HTML5ArticleTOC() }}</p>
Revertir a esta revisión