在web应用中使用文件

使用HTML5 DOM新增的File API,如今可让网页要求用户选择本地文件,而且读取这些文件的信息了。选择的方式既能够是HTML<input> 元素,也能够是拖拽 。javascript

你能够在chrome扩展等代码中使用DOM File API ;事实上有些须要注意的额外特性。参考 Using the DOM File API in chrome code 。php

访问选中的文件Edit

考虑下面的HTML:css

<input type="file" id="input">

经过File API,咱们能够在用户选取一个或者多个文件以后,访问到表明了所选文件的一个或多个File对象,这些对象被包含在一个FileList对象中.html

若是用户只选择了一个文件,那么咱们只须要访问这个FileList对象中的第一个元素.java

可使用传统的DOM选择方法来获取到用户所选择的文件:jquery

var selected_file = document.getElementById('input').files[0];

还可使用jQuery选择器来选择:web

var selectedfile = $('#input').get(0).files[0];


var selectedFile = $('#input')[0].files[0];

若是你有一个"files is undefined" 错误,那么就是你没有选择正确的HTML元素,忘记了一个jQuery选择器返回的是匹配的DOM元素的列表。用获取的DOM元素调用“files”的方法就能够了。正则表达式

在change事件发生时读取所选择的文件Edit

另外,还能够在input元素上的change事件触发时再访问它的FileList属性(但不是强制性的):chrome

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

当用户成功选取若干个文件后,handleFiles()函数会被调用,且一个表明用户所选择的文件的包含了File 对象的FileList对象会做为参数传入该函数。canvas

若是你的程序可让用户选择多个文件,记得要在input元素上加上multiple属性:

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

在用户选择了多个文件的状况下,传入handleFiles()函数的文件列表将会包含多个File对象,每一个File对象对应一个真实的文件。

动态添加change事件监听器

你还能够经过element.addEventListener()方法来添加多个change事件处理函数,像这样:

var inputElement = document.getElementById("inputField"); inputElement.addEventListener("change", handleFiles, false); function handleFiles() { var fileList = this.files; }

获取所选文件的信息Edit

用户所选择的文件都存储在了一个FileList对象上,其中每一个文件都对应了一个File对象。你能够经过这个FileList对象的length属性知道用户一共选择了多少个文件:

var numFiles = files.length;

能够经过普通的循环语句来操做每一个单独的File对象:

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

File对象上有三个属性提供了所包含文件的相关信息.

name
文件名,只读字符串,不包含任何路径信息.
size
文件大小,单位为字节,只读的64位整数.
type
MIME类型,只读字符串,若是类型未知,则返回空字符串.

例子:显示文件大小

下面的例子演示了size属性的用法:

<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>File(s) size</title> <script> function updateSize() { var nBytes = 0, oFiles = document.getElementById("uploadInput").files, nFiles = oFiles.length; for (var nFileId = 0; nFileId < nFiles; nFileId++) { nBytes += oFiles[nFileId].size; } var sOutput = nBytes + " bytes"; var aMultiples = ["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"], nMultiple = 0, nApprox = nBytes / 1024; // optional code for multiples approximation for ( ; nApprox > 1; nApprox /= 1024, nMultiple++) { sOutput = nApprox.toFixed(3) + " " + aMultiples[nMultiple] + " (" + nBytes + " bytes)"; } // end of optional code document.getElementById("fileNum").innerHTML = nFiles; document.getElementById("fileSize").innerHTML = sOutput; } </script> </head> <body onload="updateSize();"> <form name="uploadForm"> <p> <input id="uploadInput" type="file" name="myFiles" onchange="updateSize();" multiple> selected files: <span id="fileNum">0</span>; total size: <span id="fileSize">0</span> </p> <p> <input type="submit" value="Send file"> </p> </form> </body> </html>

在隐藏的文件输入框上调用click()方法Edit

从Gecko 2.0 (Firefox 4 / Thunderbird 3.3 / SeaMonkey 2.1)开始,你能够隐藏掉默认的文件输入框<input>元素,使用自定义的界面来充当打开文件选择对话框的按钮.实现起来很简单,你只须要使用样式display:none把本来的文件输入框隐藏掉,而后在须要的时候调用它的click()方法就好了.

考虑一下下面的HTML:

<input type="file" id="fileElem" multiple accept="image/*" style="display:none" onchange="handleFiles(this.files)">
<a href="#" id="fileSelect">Select some files</a>

为自定义的按钮绑定click事件:

var fileSelect = document.getElementById("fileSelect"), fileElem = document.getElementById("fileElem"); fileSelect.addEventListener("click", function (e) { if (fileElem) { fileElem.click(); } e.preventDefault(); // prevent navigation to "#" }, false);

这样,你就能任意改变这个新按钮的样式了.

经过拖放操做选择文件Edit

你可让用户将本地文件拖放到你的应用程序上.

首先要建立一个拖放操做的目的区域:

第一步是创建一个放置区域。可根据您的应用程序的设计来决定哪部分的内容接受 drop,但建立一个接收drop事件的元素是简单的:

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

在这个例子中,ID为dropbox的元素所在的区域是咱们的拖放目的区域。咱们须要在该元素上绑定dragenterdragover,drop事件。

咱们必须阻止dragenterdragover事件的默认行为,这样才能触发drop事件:

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

下面是drop()函数:

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

在该函数中,咱们从事件对象中获取到dataTransfer对象,把该对象包含的Filelist对象传入函数handleFiles(),这个函数会无区别的对待从input元素或拖放操做中来的文件列表。

例子:显示用户所选图片的缩略图Edit

假设你正在开发下一个伟大的照片分享网站,并但愿使用HTML5在用户上传他们图片以前进行缩略图预览。您能够如前面所讨论的创建一个输入元素或者拖放区域,并调用一个函数,以下面的handleFiles()函数。

function handleFiles(files) {
  for (var i = 0; i < files.length; i++) {
    var file = files[i];
    var imageType = /^image\//;
    
    if ( ) {
      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);
  }
}!imageType.test(file.type)// Assuming that "preview" is the div output where the content will be displayed

这里咱们循环处理用户选择的文件,查看每一个文件的类型属性,看看这是不是一个图像文件(经过一个正则表达式匹配字符串“image.*”)。对于每 个图片文件,咱们建立一个新的img元素。CSS能够用于创建任何漂亮的边界,阴影,和指定图像的大小,因此,甚至不须要在这里完成。

每张图片咱们添加一个obj类,让他们更容易的在DOM树中被找到。咱们也在图片上添加了一个file属性来确认每张图片的 File,这样能够帮助咱们在以后真正的上传工做时获取到图片。最后咱们使用 Node.appendChild() 把缩略图添加到咱们先前的文档区域中。

而后,咱们创建了{ { domxref(FileReader)} }来处理图片的异步加载,并把它添加到img元素上。在建立新的FileReader对象以后,咱们创建了onload函数,而后调用 readAsDataURL()开始在后台进行读取操做。当图像文件的全部内容加载后,他们转换成一个 data: URL,传递到onload回调函数中。以后只须要把img元素的src属性设置为这个加载过的图像,就可让图像的缩略图出如今用户的屏幕 上。

使用对象URLEdit

Gecko 2.0 (Firefox 4 / Thunderbird 3.3 / SeaMonkey 2.1)开始支持window.URL.createObjectURL()window.URL.revokeObjectURL()两个DOM方法。这两个方法建立简单的URL字符串对象,用于指向任何 DOM File 对象数据,包括用户电脑中的本地文件。

当你想要在HTML中经过URL来引用File对象,你能够参考以下方式建立:

var objectURL = window.URL.createObjectURL(fileObj);

URL对象是 File 对象的一个字符串标识。 每次调用window.URL.createObjectURL()的时候,会建立一个惟一的URL对象,即便你已经为该文件建立了URL对象。这些对象都必须被释放。 当文档被卸载时,它们会自动释放,若是你的页面动态地使用它们,你应该明确地经过调用window.URL.revokeObjectURL()释放它们:

window.URL.revokeObjectURL(objectURL);

例子: 使用对象URL来显示图片Edit

这个例子使用了对象URL来显示图片缩略图,同时还显示了图片的其余信息,包括图片名和图片大小,你能够查看该例子的在线演示.

负责界面呈现的HTML以下:

<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 files selected!</p> </div>

这创建文件的<input>元素就像一个调用文件选择器的连接(由于咱们要隐藏文件输入,以防止表现出不友好的UI)。这部分将在 Using hidden file input elements using the click() method里解释,由于是调用文件选择器的方法。

下面是 handleFiles()方法

window.URL = window.URL || window.webkitURL; var fileSelect = document.getElementById("fileSelect"), fileElem = document.getElementById("fileElem"), fileList = document.getElementById("fileList"); fileSelect.addEventListener("click", function (e) { if (fileElem) { fileElem.click(); } e.preventDefault(); // prevent navigation to "#" }, false); function handleFiles(files) { if (!files.length) { fileList.innerHTML = "<p>No files selected!</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(e) { 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); } }

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 object URL representing the file, using window.URL.createObjectURL() 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 object URL, since it's no longer needed once the image has been loaded. This is done by calling the window.URL.revokeObjectURL() method, passing in the object URL string as specified by img.src.
    6. Append the new list item to the list.

例子:上传用户选择的文件Edit

你能够异步的将用户所选择的文件上传到服务器上(好比一张图片).

建立上传任务

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.

实现文件上传

FileUpload函数接受两个参数:一个IMG元素,一个File对象或Blob对象.

function FileUpload(img, file) { var reader = new FileReader(); 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'); reader.onload = function(evt) { xhr.sendAsBinary(evt.target.result); }; reader.readAsBinaryString(file); }

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. The FileReader object is used to convert the file to a binary string.
  6. Finally, when the content is loaded the XMLHttpRequest function sendAsBinary() is called to upload the file's content.

异步实现文件上传

<?php if (isset($_FILES['myFile'])) { // Example: move_uploaded_file($_FILES['myFile']['tmp_name'], "uploads/" . $_FILES['myFile']['name']); exit; } ?><!DOCTYPE html> <html> <head> <title>dnd binary upload</title> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <script type="text/javascript"> function sendFile(file) { var uri = "/index.php"; var xhr = new XMLHttpRequest(); var fd = new FormData(); xhr.open("POST", uri, true); xhr.onreadystatechange = function() { if (xhr.readyState == 4 && xhr.status == 200) { // Handle response. alert(xhr.responseText); // handle response. } }; fd.append('myFile', file); // Initiate a multipart/form-data upload xhr.send(fd); } window.onload = function() { var dropzone = document.getElementById("dropzone"); dropzone.ondragover = dropzone.ondragenter = function(event) { event.stopPropagation(); event.preventDefault(); } dropzone.ondrop = function(event) { event.stopPropagation(); event.preventDefault(); var filesArray = event.dataTransfer.files; for (var i=0; i<filesArray.length; i++) { sendFile(filesArray[i]); } } </script> </head> <body> <div> <div id="dropzone" style="margin:30px; width:500px; height:300px; border:1px dotted grey;"> Drag & drop your file here... </div> </div> </body> </html>

示例: 使用URLs对象显示 PDFEdit

URLs对象不只仅是可用于图像!它们可用于显示嵌入的PDF文件,或能够由浏览器显示的任何其它资源。

在火狐中,使PDF出如今内嵌的iframe中(并不建议做为一个下载的文件),把偏好pdfjs.disabled设置为false 

<iframe id="viewer">

src 属性在这里有些变化:

var obj_url = window.URL.createObjectURL(blob);
var iframe = document.getElementById('viewer');
iframe.setAttribute('src', obj_url);
window.URL.revokeObjectURL(obj_url);

示例:其余文件类型使用URLs对象Edit

你能够用一样的方式操纵其它格式的文件。下面是如何预览上传的视频:

var video = document.getElementById('video');
var obj_url = window.URL.createObjectURL(blob);
video.src = obj_url;
video.play()
window.URL.revokeObjectURL(obj_url);
相关文章
相关标签/搜索