分片上传是一种优化大文件上传性能的技术。通过将大文件分割成多个小片段,可以并行上传,提高上传速度,并减少单个文件上传失败重传的次数。本文将详细介绍如何使用HTML5和JavaScript实现分片上传进度条,并提供一个完整的源码示例。
分片上传原理
分片上传的基本原理如下:
- 文件分割:将大文件分割成多个小块,通常是每块1MB或更大。
- 并行上传:将分割后的文件块并行上传到服务器。
- 服务器端合并:服务器端接收到所有文件块后,将它们合并成原始文件。
实现步骤
1. HTML结构
首先,我们需要一个简单的HTML结构来展示进度条和上传按钮。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>分片上传进度条实现</title>
</head>
<body>
<input type="file" id="fileInput">
<button id="uploadBtn">上传</button>
<div id="progressBarContainer">
<div id="progressBar" style="width: 0%; height: 20px; background-color: blue;"></div>
</div>
<script src="upload.js"></script>
</body>
</html>
2. JavaScript逻辑
接下来,我们需要编写JavaScript代码来处理文件选择、分割、上传和进度更新。
document.getElementById('uploadBtn').addEventListener('click', function() {
var fileInput = document.getElementById('fileInput');
var file = fileInput.files[0];
if (!file) {
alert('请选择一个文件');
return;
}
var chunkSize = 1024 * 1024; // 每个文件块的大小,1MB
var totalChunks = Math.ceil(file.size / chunkSize);
var progressBar = document.getElementById('progressBar');
progressBar.style.width = '0%';
var uploadChunk = function(chunkNumber) {
var start = chunkNumber * chunkSize;
var end = Math.min(file.size, start + chunkSize);
var chunk = file.slice(start, end);
var formData = new FormData();
formData.append('file', chunk);
formData.append('chunkNumber', chunkNumber);
formData.append('totalChunks', totalChunks);
formData.append('fileName', file.name);
// 使用XMLHttpRequest或fetch API发送请求
fetch('upload.php', {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => {
if (data.success) {
progressBar.style.width = ((chunkNumber + 1) / totalChunks) * 100 + '%';
if (chunkNumber < totalChunks - 1) {
uploadChunk(chunkNumber + 1);
} else {
alert('上传完成');
}
} else {
alert('上传失败');
}
})
.catch(error => {
console.error('上传过程中发生错误:', error);
});
};
uploadChunk(0);
});
3. 服务器端处理
服务器端需要接收文件块,存储它们,并在所有块上传完成后合并文件。以下是一个简单的PHP示例:
<?php
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$chunk = file_get_contents('php://input');
$chunkNumber = $_POST['chunkNumber'];
$totalChunks = $_POST['totalChunks'];
$fileName = $_POST['fileName'];
// 将文件块写入临时文件
$tempFile = tempnam(sys_get_temp_dir(), 'chunk');
file_put_contents($tempFile, $chunk);
// 如果是最后一个块,则进行合并
if ($chunkNumber === $totalChunks - 1) {
$destination = $fileName;
$tempFiles = glob(sys_get_temp_dir() . "/chunk*");
$fileChunks = new SplFileObject($tempFiles[0]);
$fileChunks->flock(LOCK_EX);
$fileChunks->seek(0, SEEK_END);
$fileChunks->fwrite("\n");
for ($i = 1; $i < count($tempFiles); $i++) {
$fileChunks->seek(0, SEEK_END);
$fileChunks->fwrite(file_get_contents($tempFiles[$i]));
unlink($tempFiles[$i]);
}
$fileChunks->flock(LOCK_UN);
rename($tempFile, $destination);
}
echo json_encode(['success' => true]);
} else {
http_response_code(405);
echo json_encode(['success' => false, 'message' => 'Method not allowed']);
}
?>
总结
通过以上步骤,我们可以实现一个简单的分片上传进度条。在实际应用中,可能需要添加错误处理、重试机制和安全性考虑。分片上传是一种有效提高大文件上传速度的方法,适用于需要处理大量文件的场景。
