闲云博客

关注互联网科技,记录编程点滴

HTML5之File API

| 0 comments

HTML5 File API的设计初衷,是改善基于浏览器的Web应用程序处理文件上传的方式,使文件直接拖放上传成为可能。草案定义了新的输入选项 ﹤input type=”file”﹥ 来处理文件上传。更为惊喜的是,该API为开发者提供了一个关联上传数据,并显示上传进度和其他信息的方法。

什么是File API

File API 提供了在 Web Application 客户端表现和操作文件对象的 API, 以及可编程的选择文件和访问它们的数据。包括:

  • FileList: File对象的一个类似数组的序列。(想象一下多文件上传或者直接从桌面系统拽一个文件夹的情形)

  • File: 表示 FileList 中的一个单独的文件;提供了诸如文件名,文件大小,mimetype,以及一个到文件句柄的引用。

  • Blob: 表示可变的原始数据。提供了可以把数据按字节区间切片成更小块的原始数据的方法。还提供了表示数据块大小的属性。File接口是从这个接口继承的。

  • FileReader: 可以把 File 或者 Blob 对象读进内存,并且可以使用进度事件和进度处理器属性访问这些 Files 或者 Blobs 的数据。

使用 Input 表单元素选择文件

<input type="file" id="files" name="files[]" multiple />
<output id="list"></output>
function handleFileSelect(evt) {
  var files = evt.target.files;
  var output = [];
  for (var i=0, f; f = files[i]; i++) {
    output.push('<li><strong>', escape(f.name), 
    '</strong> (', f.type || 'n/a', ') -', 
      f.size, ' 字节, 最后修改: ', 
      f.lastModifiedDate ? f.lastModifiedDate.toLocaleDateString() : 'n/a', '</li>');
  }
    document.getElementById('list').innerHTML = '<ul>' + output.join('') + '</ul>';
}
document.getElementById('files').addEventListener('change', handleFileSelect, false);

使用拖拽方式选择文件

<div class="example">
  <div id="drop-zone">把文件拖拽到这里</div>
  <output id="list2"></output>
</div>
function handleFileSelect2(evt) {
  evt.stopPropagation();  
  evt.preventDefault();
  var files = evt.dataTransfer.files;  
  var output = [];
  for (var i=0, f; f = files[i]; i++) {
    output.push('<li><strong>', escape(f.name), '</strong> (', f.type || 'n/a', ') -', 
      f.size, ' 字节, 最后修改: ', f.lastModifiedDate ? f.lastModifiedDate.toLocaleDateString() : 'n/a', '</li>');
  }
  document.getElementById('list').innerHTML = '<ul>' + output.join('') + '</ul>';
}
                  
function handleDragOver(evt) {
  evt.stopPropagation();  
  evt.preventDefault();
  evt.dataTransfer.dropEffect = 'copy';
}
var dropZone =  document.getElementById('drop-zone');
dropZone.addEventListener('dragover', handleDragOver, false);
dropZone.addEventListener('drop', handleFileSelect2, false);

FileReader

FileReader 包含四种异步读取文件的方式:

  • FileReader.readAsBinaryString(Blob|File) – result 属性包含的是 file/blob 的二进制字符串形式的数据。每个字节由一个 0-255 的整数表示。

  • FileReader.readAsText(Blob|File, opt_encoding) – result 属性包含的是以文本方式表示的 file/blob 数据。默认情况下,字符串以'UTF-8'编码方式解码。使用 opt_encoding 参数可以指定一个不同的格式。

  • FileReader.readAsDataURL(Blob|File) – result 属性包含的是以data URL编码的 file/blob 数据。

  • FileReader.readAsArrayBuffer(Blob|File) – result属性包含的是以ArrayBuffer对象表示的 file/blob 数据。

一旦这些read方法被调用,onloadstart, onprogress, onload, onabort, onerror, onloadend 就可以被用来追踪进度。

readAsDataURL示例

function handleFileSelect3(evt) {
  var files = evt.target.files;
  for (var i=0, f; f = files[i]; i++) {
    if (!f.type.match('image.*')) {
      continue;
    }
    var reader = new FileReader();
    reader.onload = (function(theFile) {
        return function(e) {
          // Render thumnial
          var span = document.createElement('span');
          span.innerHTML = ['<img class="thumb" src="', e.target.result,
          '" title="', escape(theFile.name), '"/>'].join('');
          document.getElementById('thumbnails').insertBefore(span, null);
        };
      })(f);
    reader.readAsDataURL(f);    
  }
}

文件切片

File 接口提供了 slice 方法支持把文件切成不同的片段,第一个参数是起始的字节数,第二个参数是结束的字节数,还有一个可选的内容类型字符串可以作为第三个参数:

var blob = file.slice(startingByte, endingByte);
reader.readAsBinary(blob);

slice示例

<div class="example">
    <input type="file" id="files4" name="file4" /> 读取字节数: 
    <span class="readBytesButtons">
      <button data-startbyte="0" data-endbyte="79">1-80</button>
      <button data-startbyte="99" data-endbyte="149">100-150</button>
      <button data-startbyte="9" data-endbyte="19">10-20</button>
      <button>整个文件</button>
    </span>
    <div id="byte_range"></div>
    <div id="byte_content"></div>  
</div>
function readBlob(opt_startByte, opt_stopByte) {
  var file = document.getElementById('files4').files[0];
  var start = parseInt(opt_startByte) || 0;
  var stop = parseInt(opt_stopByte) || file.size - 1;
  var reader = new FileReader();
  reader.onloadend = function(evt) {
    if (evt.target.readyState == FileReader.DONE) {
      document.getElementById('byte_content').textContent = evt.target.result;
      document.getElementById('byte_range').textContent = 
          ['Read bytes: ', start + 1, ' - ', stop + 1,
           ' of ', file.size, ' byte file'].join('');
    }
  };
        
  var blob = file.slice(start, stop + 1);
  reader.readAsBinaryString(blob);
}
document.querySelector('.readBytesButtons').addEventListener('click', function(evt) {
    if (evt.target.tagName.toLowerCase() == 'button') {
        var startByte = evt.target.getAttribute('data-startbyte');
        var endByte = evt.target.getAttribute('data-endbyte');
        readBlob(startByte, endByte);
    }
}, false);

监视文件读取进度

可以使用 onloadstart 和 onprogress 事件来监视读取进度。

<div class="example">
    <input type="file" id="files5" name="file5" />
    <button id="abort-read">停止读取</button>
    <div id="progress_bar"><div class="percent">0%</div></div>
</div>
var reader;
var progress = document.querySelector('.percent');
   
function abortRead() {
    reader.abort();
}
   
function errorHandler(evt) {
    switch(evt.target.error.code) {
        case evt.target.error.NOT_FOUND_ERR:
            alert('文件不存在!');
            break;
        case evt.target.error.NOT_READABLE_ERR:
            alert('文件不可读!');
            break;
        case evt.target.error.ABORT_ERR:
            break; // noop
        default:
            alert('出错啦!');
    };
}
   
function updateProgress(evt) {
    // evt is an ProgressEvent.
    if (evt.lengthComputable) {
        var percentLoaded = Math.round((evt.loaded / evt.total) * 100);
        // Increase the progress bar length.
        if (percentLoaded < 100) {
            progress.style.width = percentLoaded + '%';
            progress.textContent = percentLoaded + '%';
        }
    }
}
   
function handleFileSelect5(evt) {
    // Reset progress indicator on new file selection.
    progress.style.width = '0%';
    progress.textContent = '0%';
   
    reader = new FileReader();
    reader.onerror = errorHandler;
    reader.onprogress = updateProgress;
    reader.onabort = function(e) {
        alert('文件读取操作被取消');
    };
    reader.onloadstart = function(e) {
        document.getElementById('progress_bar').className = 'loading';
    };
    reader.onload = function(e) {
        // Ensure that the progress bar displays 100% at the end.
        progress.style.width = '100%';
        progress.textContent = '100%';
        setTimeout("document.getElementById('progress_bar').className='';", 2000);
    }
   
    // Read in the image file as a binary string.
    reader.readAsBinaryString(evt.target.files[0]);
}
   
document.getElementById('files5').addEventListener('change', handleFileSelect5, false);
document.getElementById('abort-read').addEventListener('click', abortRead, false);

原创文章,转载请注明: 转载自闲云博客

本文链接地址: HTML5之File API

Author: Jian Yun

Hi,我是闲云,感谢您阅读我的博客。我是一个微软ASP.NET方面的开发者,写写博客分享下互联网科技方面感兴趣的事和记录自己程序开发中的点点滴滴。 ------“立志难也,不在胜人,在自胜”

发表评论

Required fields are marked *.