相关文章推荐
打篮球的煎饼  ·  .net core ...·  3 周前    · 
火爆的香瓜  ·  用SqlParameter ...·  1 年前    · 
聪明的花生  ·  想要让你的SQL ...·  1 年前    · 
绅士的蚂蚁  ·  mac下jupyternotebook ...·  1 年前    · 

在日常工作中,文件上传是一个非常常见的功能。在项目开发中,我们通常都会使用一些成熟的上传组件来实现对应的功能。

一般来说,成熟的上传组件不仅会提供漂亮的UI或好的交互体验,但是对于一些文件小的上传方式是可以满足的,那么如果文件过大呢就有点满足不了。

那么接下来我们一起来看看,如何实现大文件的上传吧,由于内容比较多,可能会分几篇文章进行描述,今天会详细简述如何优雅判断文件的上传格式。

我们先来实现简单的上传功能。

创建html文件,使用input的file文件进行文件获取,使用button点击进行上传操作。

<!DOCTYPE html>
<html lang="en">
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>文件上传</title>
</head>
  <div id="warp" style="height: 100px; border: 4px dashed #eee; text-align: center; line-height: 100px;">
    <input type="file" id="file">
  </div>
  <button id="btn">上传</button>
</body>

创建js文件,获取指定元素加入方法。

const fileEle = document.getElementById('file')
const btnEle = document.getElementById('btn')
let file = null // 文件流
fileEle.addEventListener('change', function (e) {
  file = e.target.files[0]
async function uplodaFile(params) {
  if (await isImage(file)) {
    console.log('文件格式正确')
  } else {
    console.log('文件格式不对')
btnEle.addEventListener('click', async function (e) {
  e.preventDefault()
  uplodaFile()

编写isImage函数使用文件转换二进制的方式来判断文件格式,这样可以很好的避免恶意文件。

// 文件流转换二进制
function blobToString(blob) {
  return new Promise(resolve => {
    // 读取文件流
    const reader = new FileReader()
    reader.onload = function () {
      // 文件截取并转换charCodeAt在进行16进制转换拿到文件的二进制
      const ret = reader.result.split('')
        .map(v => v.charCodeAt())
        .map(v => v.toString(16).toUpperCase())
        .join(' ')
      resolve(ret)
    reader.readAsBinaryString(blob)
// 判断文件是不是jpg的,分别取文件流二进制的前2个和后2个
async function isJpg(file) {
  const len = file.size
  const start = await blobToString(file.slice(0, 2))
  const tail = await blobToString(file.slice(-2, len))
  const isJpg = (start == 'FF D8') && (tail == 'FF D9')
  return isJpg
// 判断文件是不是gif的,取文件二进制的前6个
async function isGif(file) {
  const ret = await blobToString(file.slice(0, 6))
  return isGIf = (ret == '47 49 46 38 39 61') || (ret == '47 49 46 38 37 61')
// 判断文件是不是png的,取文件二进制的前8个
async function isPng(file) {
  const ret = await blobToString(file.slice(0, 8))
  return isPng = ret == '89 50 4E 47 0D 0A 1A 0A'
// 判断文件
function isImage(file) {
  return isJpg(file) || isGif(file) || isPng(file)

为了实现更好的体验,我们在加入拖拽上传的功能。

const warpEle = document.getElementById('warp')
// 拖拽
fileEle.addEventListener('drop', e => {
  e.preventDefault()
  file = e.dataTransfer.files[0]
  warpEle.style.borderColor = '#eee'
// 拖拽进入
fileEle.addEventListener('dragover', e => {
  warpEle.style.borderColor = 'red'
  e.preventDefault()
// 拖拽离开
fileEle.addEventListener('dragleave', e => {
  warpEle.style.borderColor = '#eee'
  e.preventDefault()

如果是pdf文件,普通的上传文件组件如果修改pdf后缀改为png或者jpg就可以上传成功,这种是比较危险,如果是恶意文件就会导致程序出现问题,转换二进制的方式不管怎么修改文件后缀文件流信息不变,就会上传不成功,这样就有效限制文件格式了。

为了用户体验我们还加入了文件拖拽上传的功能。这样的话,文件上传 + 拖拽文件上传 + 文件上传格式的校验我们就做完了。

目前的文件上传还是有一定的问题,比如文件名称如果一样怎么限制,文件过大断网怎么上传,所以下一篇我们讲解文件名称转换MD5值进行上传。

xdm,尽情期待吧。

分类:
前端
标签: