base64的数据型文件在HTML中被使用(引用)已经不是什么新鲜事儿了。我们可以用很简单的几行代码就能写个本地的转换器:

<input type="file" id="fileInput">
<output id="output"></output>

<script type="text/javascript">
var fileInput = document.getElementById('fileInput'),
    output = document.getElementById('output'),
    reader = new FileReader();

fileInput.onchange = function(e){
    var file = e.target.files[0];
    reader.readAsDataURL(file);
}

reader.onload = function(e){
   output.innerHTML = e.target.result;
}
</script>

下面是Demo,你可以尝试一下:

你也可以用拖拽的方式来获取文件:

<div id="dragInput">快到碗里来</div>
<output id="output4drag"></output>
<script type="text/javascript">
var dragInput = document.getElementById('dragInput'),
    output4drag = document.getElementById('output4drag'),
    reader4drag = new FileReader();
dragInput.ondragover = function(event){
    event.stopPropagation();
    event.preventDefault();
    event.dataTransfer.dropEffect = 'copy'; 
};
dragInput.ondrop = function(event){
    event.stopPropagation();
    event.preventDefault();
    var file = event.dataTransfer.files[0];
    reader4drag.readAsDataURL(file);
};
reader4drag.onload = function(e){
   output4drag.innerHTML = e.target.result;
}
</script>

你可以把任意文件拖放到下面的区域里:

快到碗里来

得到的base64数据可以直接赋值给一些元素的src属性,比如<script>、<img>、<video>等,这对于我们想开发更多离线功能来说确实是一个福音。

然而,你用这种办法来转一些图片是没什么问题,因为它们不会大到哪里去。而我遇到的问题是我想在本地以一个视频为蓝本获取一些播放信息(这句话好拗口,其实我就是想“打点”,估计也没几个人明白……)。那么问题来了,我找了一部《美女与野兽》,时长1个多小时,视频文件大小350M左右。这个可能比日常处理的目标视频稍大一点,但是这显然不是问题的关键。问题在于用FileReader读取大文件时浏览器(Chrome)会崩溃!因为当readAsDataURL把文件转码成base64数据时,文件有多大base64数据只可能更大,内存中就要维护这么一份数据,而再将它作为 src给video对象时,播放器还要重新把这份base64的数据解码后渲染,可想而之对于一个350M的文件,仅仅两行代码就带来至少700M左右的内存消耗,当然浏览器就挂了。

HTML5有个新的API,只这一句代码,你想引用多大的本地文件都可以,那就是:

var url = window.URL.createObjectURL(file);

这句代码会返回这个本地file的URL映射,你可以在Chrome浏览器里输入chrome://blob-internals/来查看它为你生成的形如blob:http%3A//www.codingserf.com/c85ddc34-8a8e-4dac-93fa-9ab008a8ad3e这样的链接 ,那么你就可以把这个url赋值给那些src了。浏览器做的工作只是一个映射,没有什么转码解码,当然就不会受文件大小的限制。

一般情况下浏览器会在页面关闭(准确地说是unload) 时会释放这些链接。但是为了保险起见我们会选择手动删除,也是一点优化吧:

window.URL.revokeObjectURL(url)

好了,结论是base64不适合大文件,显而易见。