文件分片上传
前端
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>文件上传</title>
</head>
<body>
<input type="file" id="file-upload" name="">
<button class="upload-btn" onclick="upload(0)">上传</button>
</body>
<script src="https://cdn.bootcdn.net/ajax/libs/axios/0.19.2/axios.min.js"></script>
<script>
const uploadBtn = document.querySelector('.upload-btn')
const uploadFile = document.querySelector('#file-upload')
const chunkSize = 1024*1024
function upload(index) {
try {
const file = uploadFile.files[0]
let [fName, suffix] = file.name.split('.')
let single = index * chunkSize
if(single > file.size) {
merge(file.name)
return false
}
let block = file.slice(single, single + chunkSize)
let blockName = `${fName}.${index}.${suffix}`
let blockFile = new File([block], blockName)
let formData = new FormData()
formData.append('file', blockFile)
axios.post('/upload', formData).then((res) => {
if(res.status === 200) {
console.log(res)
upload(++index)
}
})
} catch (e) {
console.log(e)
}
}
function merge(name) {
try {
axios.post('/merge', {name: name}).then(res => {
if(res === 200) {
return res.url
} else {
console.error('文件上传失败')
}
})
} catch(e) {
console.log(e)
}
}
</script>
</html>
后端
const express = require('express')
const bodyParser = require('body-parser')
const multiparty = require('multiparty')
const fse = require('fs-extra')
const path = require('path')
const fs = require('fs')
const app = express()
app.use(express.static(__dirname + '/public'))
app.use(bodyParser.urlencoded({extended: true}))
app.use(bodyParser.json())
const UPLOAD_DIR = path.resolve(__dirname, 'public/upload')
app.post('/upload', (req, res) => {
const form = new multiparty.Form({uploadDir: 'temp'})
form.parse(req)
form.on('file',async (name, chunk) => {
console.log(chunk)
let chunkDir = `${UPLOAD_DIR}/${chunk.originalFilename.split('.')[0]}`
if(!fse.existsSync(chunkDir)) {
await fse.mkdirs(chunkDir)
}
var dPath = path.join(chunkDir, chunk.originalFilename.split('.')[1])
await fse.move(chunk.path, dPath, {overwrite: true})
})
res.send('文件上传成功')
})
app.post('/merge', async (req, res) => {
let { name } = req.body
let fName = name.split('.')[0]
let chunkDir = path.join(UPLOAD_DIR, fName)
let chunks = await fse.readdir(chunkDir)
chunks.sort((a, b) => a - b ).map(chunkPath => {
fs.appendFileSync(
path.join(UPLOAD_DIR, name),
fs.readFileSync(`${chunkDir}/${chunkPath}`)
)
})
fse.removeSync(chunkDir)
res.send({
msg: '文件合并成功',
url: `http://localhost:3000/upload/${name}`
})
})
app.listen(3000, () => {
console.log('port: 3000')
})
参考摘自 :B站itvlog
项目git 地址