Skip to content

Latest commit

 

History

History
130 lines (115 loc) · 3.33 KB

06 文件切片上传.md

File metadata and controls

130 lines (115 loc) · 3.33 KB
  • 客户端
const CHUNK_SIZE = 1024 * 1024 // 每个切片的大小
let file // 选择的文件对象
let currentChunk = 0 // 当前上传的切片序号
let totalChunks = 0 // 总切片数
let uploadUrl = 'http://localhost:3000' // 上传接口的 URL

// 选择文件时触发
document
	.getElementById('file-input')
	.addEventListener('change', function (event) {
		file = event.target.files[0]
		totalChunks = Math.ceil(file.size / CHUNK_SIZE)
	})

// 点击上传按钮时触发
document.getElementById('upload-button').addEventListener('click', function () {
	if (!file) {
		alert('请先选择文件')
		return
	}
	uploadChunk()
})
//
// 上传切片
function uploadChunk() {
	let start = currentChunk * CHUNK_SIZE
	let end = Math.min(start + CHUNK_SIZE, file.size)
	let chunk = file.slice(start, end) // 从文件中获取当前切片的数据

	let formData = new FormData()
	formData.append('file', chunk, file.name)
	formData.append('chunk', currentChunk)
	formData.append('totalChunks', totalChunks)

	fetch(uploadUrl, {
		method: 'POST',
		body: formData,
	})
		.then(function (response) {
			if (response.ok) {
				// 切片上传成功,继续上传下一个切片
				currentChunk++
				if (currentChunk < totalChunks) {
					uploadChunk()
				} else {
					// 所有切片上传完成
					console.log('文件上传完成')
				}
			} else {
				// 切片上传失败,重试该切片
				console.error('切片上传失败')
				uploadChunk()
			}
		})
		.catch(function (error) {
			// 切片上传失败,重试该切片
			console.error('切片上传失败')
			console.error(error)
			uploadChunk()
		})
}
  • 服务器端
const express = require('express')
const multer = require('multer')
const path = require('path')
const fs = require('fs')

const app = express()
const PORT = 3000

app.use(express.static('/index', path.join(__dirname, './文件上传.html')))
const uploadDir = path.join(__dirname, 'uploads')
if (!fs.existsSync(uploadDir)) {
	fs.mkdirSync(uploadDir)
}

const storage = multer.diskStorage({
	destination: uploadDir,
	filename: function (req, file, callback) {
		let ext = path.extname(file.originalname)
		let name = path.basename(file.originalname, ext)
		let chunk = req.body.chunk
		callback(null, `${name}-${chunk}${ext}`)
	},
})

const upload = multer({
	storage: storage,
})
app.post('/upload', upload.single('file'), function (req, res) {
	let chunk = parseInt(req.body.chunk)
	let totalChunks = parseInt(req.body.totalChunks)

	if (chunk === totalChunks - 1) {
		// 所有切片上传完成,将所有切片合并成一个文件
		let ext = path.extname(req.file.originalname)
		let name = path.basename(req.file.originalname, ext)
		let filePath = path.join(uploadDir, `${name}${ext}`)

		let writeStream = fs.createWriteStream(filePath)
		for (let i = 0; i < totalChunks; i++) {
			let chunkFilePath = path.join(uploadDir, `${name}-${i}${ext}`)
			let readStream = fs.createReadStream(chunkFilePath)
			readStream.pipe(writeStream)
		}

		writeStream.on('close', function () {
			// 删除所有切片文件
			for (let i = 0; i < totalChunks; i++) {
				let chunkFilePath = path.join(uploadDir, `${name}-${i}${ext}`)
				fs.unlinkSync(chunkFilePath)
			}

			res.sendStatus(200)
		})
	} else {
		res.sendStatus(200)
	}
})

app.listen(PORT, function () {
	console.log(`文件切片上传示例运行在 http://localhost:${PORT}`)
})