Los resultados de tu búsqueda

    Utilización de ficheros desde aplicaciones web

    This translation is incomplete. Please help translate this article from English.

     

    Utilizando la API File añadida al DOM en HTML5, es posible para el usuario seleccionar ficheros locales desde la web, de manera que se pueden leer los contenidos de esos ficheros. Ésta selección la puede hacer cualquiera usando un elemento input de HTML, o mediante un drag and drop.

    Selección de ficheros utilizando HTML

    Seleccionar solo un fichero usando la API File es sencillo:

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

    Cuando el usuario elige el fichero, la función handleFiles() es llamada con un objeto FileList el cual a su vez contiene un objeto File que representa el fichero elegido por el usuario.

    Si se prefiere permitir al usuario elegir varios ficheros, entonces se pone el atributo multiple en el elemento input:

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

    En este caso, la lista de ficheros pasada a la función handleFiles() contiene un objeto File por cada fichero seleccionado por el usuario. 

    (Firefox 4 / Thunderbird 3.3 / SeaMonkey 2.1)

    Using hidden file input elements using the click() method

    Comenzando en Gecko 2.0 (Firefox 4 / Thunderbird 3.3 / SeaMonkey 2.1), se puede ocultar el realmente feo <input> y representar tu propio interfaz para abrir el picker de ficheros y pintar que fichero o ficheros ha seleccionado el usuario. Esto se puede hacer añadiendo al elemento input la característica "display:none" en su css, o estilo y llamando al método click() del elemento <input>.

    Como aparece en este 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 método doClick() puede parecerse al siguiente:

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

    Obviamente puedes cambiar como quieras, el estilo del botón para abrir el picker de ficheros.

    Añadir dinámicamente un listener tipo change

    Si tu campo input ha sido creado usando una libreria JavaScript como jQuery, se necesitara usar element.addEventListener() para añadir el manejador de eventos tipo change, como en el ejemplo siguiente:

    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: en este caso, la función handleFiles() mira la lista de ficheros con la finalidad de aceptar un parametro, mientras los eventos listeners sean añadidos de esta manera no pueden aceptar un parametro del input.

    (Firefox 4 / Thunderbird 3.3 / SeaMonkey 2.1)

    Using blob URLs

    Gecko 2.0 (Firefox 4 / Thunderbird 3.3 / SeaMonkey 2.1) introduce soporte para los métodos de DOM window.createBlobURL() y window.revokeBlobURL(). El cual te permite crear un simple string con la URL que referenciar cualquier dato que pueda referenciar usando un objeto File DOM, esto incluye los ficheros locales del usuario del dispositivo.

    Cuando tienes un objeto File te gusta poder referenciarlo con una URL desde el HTML, la manera de crear tu propio blob URL para poder hacer esto es la siguiente:

    var blobURL = window.createBlobURL(fileObj);
    

    El blob URL es un string que identifica el objeto File. Cada vez que se llama a window.createBlobURL(), un único blob URL se crea. Cada vez que esto pasa debe de ser liberado. Cuando el documento se cierra, se libera automáticamente, pero si tu página lo usa dinámicamente deberás liberarlos explicitamente llamando a window.revokeBlobURL():

    window.revokeBlobURL(blobURL);
    

    Selección de ficheros usando drag and drop

    También se puede dejar al usuario arrastrar los ficheros en tu aplicación web.

    El primer paso para establecer la zona de arrastre, el lugar en donde dejar los ficheros arrastrados. La parte exacta en donde se coloque esta zona de arrastre dentro de tu aplicación, dependerá del diseño de la aplicación, pero crear el elemento es sencillo:

    var dropbox;
    
    dropbox = document.getElementById("dropbox");
    dropbox.addEventListener("dragenter", dragenter, false);
    dropbox.addEventListener("dragover", dragover, false);
    dropbox.addEventListener("drop", drop, false);
    

    En este ejemplo se transforma el elemento de ID "dropbox" en la zona de arrastre. Esto se hace añadiendo listeners para lo eventos de dragenter, dragover, y drop.

    Realmente en este caso no se necesita hacer nada con los eventos dragenter y dragover, por lo que ambas funciones seran muy sencillas. Sólo pararán la propagacion de eventos y prevendran las acciones por defecto:

    function dragenter(e) {
      e.stopPropagation();
      e.preventDefault();
    }
    
    function dragover(e) {
      e.stopPropagation();
      e.preventDefault();
    } 
    

    La verdadera magia ocurre en la función drop():

    function drop(e) {
      e.stopPropagation();
      e.preventDefault();
    
      var dt = e.dataTransfer;
      var files = dt.files;
    
      handleFiles(files);
    }
    

    Aquí se recupera el campo dataTransfer del evento, a partir de ahi se extraen la lista de ficheros, y se pasan a handleFiles(). A partir de este punto se manejan los ficheros de igual manera tanto si se han obtenido usado el elemento input o drag and drop.

    Recuperando la información de los ficheros selecionados

    El objeto FileList es dado por el DOM y lista todos los ficheros selecionados por el usuario, cada uno es un objeto File. Para determinar el número de ficheros que han sido seleccionados se comprueba la longitud de la lista con el atributo length:

    var numFiles = files.length;
    

    Al objeto File se accede de manera sencilla, accediendo a la lista como si fuera un array:

    for (var i = 0; i < files.length; i++) {
      var file = files[i];
      ..
    }
    

    El bucle itera por todos los ficheros de la lista.

    Cada objeto File tiene tres atributos que contienen información util sobre el fichero.

    name
    Es de solo lectura y es el nombre del fichero sin ninguna información sobre el path.
    size
    Es de solo lectura y es el tamaño del fichero en bytes como un entero de 64-bit.
    type
    The MIME type of the file as a read-only string, or "" if the type couldn't be determined.

    Example: Showing thumbnails of user-selected images

    Let's say you're developing the next great photo-sharing web site, and want to use HTML5 to display thumbnail previews of images before the user actually uploads them. Simply establish your input element or drop zone as discussed previously, and have them call a function such as the handleFiles() function below.

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

    Here our loop handling the user-selected files looks at each file's type attribute to see if it's an image file (by doing a regular expression match on the string "image.*"). For each file that is an image, we create a new img element. CSS can be used to establish any pretty borders, shadows, and to specify the size of the image, so that doesn't even need to be done here.

    Each image has the CSS class "obj" added to it, to make them easy to find in the DOM tree. We also add a file attribute to each image specifying the File for the image; this will let us fetch the images for actually uploading later. Finally, we use Node.appendChild() to add the new thumbnail to the preview area of our document.

    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.

    (Firefox 4 / Thunderbird 3.3 / SeaMonkey 2.1)

    Example: Using blob URLs to display images

    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 <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 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 <div> with the ID "fileList". This is the block into which we'll insert out file list, including thumbmails.

    If the 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 (<ul> element is created.
    2. The new list element is inserted into the <div> block by calling its element.appendChild() method.
    3. For each File in the FileList represented by files:
      1. Create a new list item (<li>) element and insert it into the list.
      2. Create a new image (<img>) element.
      3. Set the image's source to a new blob URL representing the file, using 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 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 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

    Etiquetas y colaboradores del documento

    Etiquetas:
    Colaboradores de esta página: teoli, Izel, mare
    Última actualización por: teoli,