使用 javascript 来操作文件,是严格被禁止的,因为你不想一打开网页,硬盘灯就狂闪,然后把你硬盘的文件/列表都慢慢的上传上去,那么你就危险了。所以一般情况下,javascript 操作文件,都是在网页中提供文件上传控件。此时,你需要允许,才会使此网页获得相应的文件的信息。HTML5 以前的文件上传控件,都是以

<input type="file">

来进行的,此时,我们会得到关于此文件的一些信息,包括。

name – 文件名
size – 文件大小
type – 文件的 MIME 类型。

而此时你就可以随时访问这些文件的属性而不用直接去操作文件。那么就用正常的表单方式上传就可以了。

获得文件属性

在点击浏览添加完文件之后,就可以使用如下的 javascript 代码来获取相应的文件属性了。此处使用了添加事件(change)的方式,当然一旦选择了文件之后,这些属性随时都可以获得。

<input type="file" id="your-files" multiple>
<script>
var control = document.getElementById("your-files");
control.addEventListener("change", function(event) {
    // 当 control 改变的时候
    var i = 0,
        files = control.files,
        len = files.length;
    for (; i < len; i++) {
        console.log("Filename: " + files[i].name);
        console.log("Type: " + files[i].type);
        console.log("Size: " + files[i].size + " bytes");
    }
}, false);
</script>

当 your-files 这个对象发生改变的时候,就执行下面的代码。

拖动上传/Drag and drop

虽然之前的文件上传方式可以使用,但是总是不人性化,操作起来比较麻烦,而且还不强大。(其实我认为拖动上传也不人性化,最大化浏览器好好地,要上传了,先缩小浏览器窗口,然后在拖动?麻烦不!)
但是拖动上传总有他的优点呢。并且 html5 相对来说,给了上传文件更多的属性和事件。

例如,如下代码:

<div id="your-files">&lt;/div>
<script>
var target = document.getElementById("your-files");

target.addEventListener("dragover", function(event) {
    event.preventDefault();
}, false);

target.addEventListener("drop", function(event) {

    // 阻止浏览器默认动作
    event.preventDefault();

    var i = 0,
        files = event.dataTransfer.files,
        len = files.length;

    for (; i < len; i++) {
        console.log("Filename: " + files[i].name);
        console.log("Type: " + files[i].type);
        console.log("Size: " + files[i].size + " bytes");
    }

}, false);
</script>

当你将文件拖动到 your-files 区域的时候,就可以看到 控制台 里面输出文件的信息了。当然,此时还不能上传。

使用 Ajax 上传

获得此文件以及相应的信息之后,就可以开始上传了。当然这里使用 ajax 方式上传。使用了定义在 XMLHttpRequest Level 2 中的 FormData 对象,可以表示一个 HTML 表单,并且使用“属性:值” 这样的方式,使用 append() 方法来提交表单。

var form = new FormData();
form.append("name", "Nicholas");

FormData 对象的好处就是可以直接的获取文件内容。并且可以十分有效的模拟一个表单,而你只需要增加一些特别的信息,例如文件名等,其他的浏览器都会自己去做。

// 创建一个有多个数据的表单
var form = new FormData();
form.append("name", "Nicholas");
form.append("photo", control.files[0]);

// 通过 XHR 传送,没有传送 header!
var xhr = new XMLHttpRequest();
xhr.onload = function() {
    console.log("Upload complete.");
};
xhr.open("post", "/entrypoint", true);
xhr.send(form);

一旦通过 send() 方法提交表单之后,浏览器就会同时将 header 信息也提交给服务器。所以不用担心文件的编码问题。其实就像原始的表单提交一样,例如此处,对于 php 来说,就可以使用:

$_POST["name"];
$_POST["photo"];

来获取相应文件的信息了。不过目前只有现代浏览器才支持,例如 IE 要等到 10 才行。

下一节,虽然添加,上传文件很简单,这么点就弄完了,但是如何获取文件数据呢?这就是下节要讨论的了。

一些相关的链接:
File API specification (草案)(英文)
HTML5 Drag and Drop(英文)
XMLHttpRequest Level 2(英文)