上次关于在使用分销主机时遇到的一个问题是不能上传和保存大文件,限制是20M
于是只有通过分片来解决,但是技术有限,问了文心一言得到以下答案
在本地,小文件是成功的,但是大文件失败,分割成功,下载后的文件是错误的
有没有会的老铁给优化下
对于chunkSize的大小,试过5M,但是move_uploaded_file会失败,一个很奇怪的问题
前端部分
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>文件分块上传示例</title>
</head>
<body>
<input type="file" id="fileInput" /> <br/>
<button id="uploadButton">上传文件</button>
<progress id="progressBar" value="0" max="100" style="width: 300px;"></progress>
<div id="status"></div>
</body>
</html>
<script>
document.getElementById('uploadButton').addEventListener('click', function() {
var fileInput = document.getElementById('fileInput');
var file = fileInput.files[0];
var chunkSize = 4*1024*1024; // 5MB,可以根据需要进行调整
var totalChunks = Math.ceil(file.size / chunkSize);
var chunks = [];
var progressBar = document.getElementById('progressBar');
var status = document.getElementById('status');
// 创建进度条
progressBar.value = 0;
progressBar.max = totalChunks;
// 分割文件块并上传
for (var i = 0; i < totalChunks; i++) {
var start = i * chunkSize;
var end = Math.min(start + chunkSize, file.size);
var chunk = file.slice(start, end);
chunks.push(chunk);
uploadChunk(i, chunks);
}
});
function uploadChunk(index, chunks) {
var fileInput = document.getElementById('fileInput');
var chunk = chunks[index];
var formData = new FormData();
formData.append('chunk', chunk);
formData.append('chunkIndex', index);
formData.append('totalChunks', chunks.length);
formData.append('fileName', fileInput.files[0].name);
var xhr = new XMLHttpRequest();
xhr.open('POST', 'upload.php', true); // 替换为实际的上传URL
xhr.upload.onprogress = function(e) {
var progress = (e.loaded / e.total) * 100;
document.getElementById('progressBar').value = Math.round(progress);
document.getElementById('status').textContent = '上传进度:' + progress + '%';
};
xhr.onload = function() {
if (xhr.status === 200) { // 假设服务器返回200表示上传成功
if (index === chunks.length - 1) { // 如果是最后一个块,发送完成信号给服务器处理后续操作(例如合并文件块)
document.getElementById('status').textContent = '上传完成';
//var completeData = new FormData();
//completeData.append('chunks', JSON.stringify(chunks)); // 将文件块列表转换为JSON字符串发送给服务器进行合并等操作
//completeData.append('fileName', document.getElementById('fileInput').files[0].name); // 可选,用于服务器识别文件名等元数据,根据实际需求进行修改。
//var xhrComplete = new XMLHttpRequest();
//xhrComplete.open('POST', '/complete', true); // 替换为实际的完成上传的URL(例如合并文件块的URL)
//xhrComplete.send(completeData); // 发送完成信号给服务器处理后续操作(例如合并文件块)
} else { // 如果不是最后一个块,继续上传下一个块
uploadChunk(index + 1, chunks); // 递归调用,继续上传下一个块
}
} else { // 上传失败,根据实际情况处理错误情况,例如显示错误信息给用户等。此处仅为示例,未处理错误情况。
console.error('上传失败');
}
};
xhr.send(formData); // 发送块数据到服务器进行上传操作。
}
</script>
上传部分
<?php
$targetDir = 'uploads/'; // 目标目录
$targetFile = $targetDir .$_POST['fileName'].'.part'.$_POST['chunkIndex'] ;
$fileTmp = $_FILES['chunk']['tmp_name'];
if (is_uploaded_file($fileTmp)){
if (move_uploaded_file($fileTmp, $targetFile)) {
echo '文件上传成功!';
} else {
echo '文件上传失败!';
}
}else{
echo '文件不存在!';
}
下载部分
<?php
$targetDir = 'uploads/'; // 替换为您想要存储文件的目录
$fileName = isset($_GET['name']) ? $_GET['name'] : '';
$targetFile = 'uploads/' . $fileName; // 替换为您存储文件的路径和文件名
$fileParts = glob("{$targetDir}{$fileName}.part*"); // 获取所有片段文件
sort($fileParts); // 对片段文件进行排序(按数字顺序)
$totalParts = count($fileParts); // 获取总片段数
$currentPart = 0; // 当前片段索引
header('Content-Type: application/octet-stream'); // 设置内容类型为二进制流
header('Content-Disposition: attachment; filename="' . $fileName . '"'); // 设置下载文件的名称
header('Content-Transfer-Encoding: binary'); // 设置传输编码为二进制流
header('Accept-Ranges: bytes'); // 设置接受范围为字节范围
while ($currentPart < $totalParts) {
$partFile = array_shift($fileParts); // 获取当前片段文件名(按数字顺序)
$fileSize = filesize($partFile); // 获取当前片段大小(字节数)
//$s = $currentPart-($currentPart + $fileSize - 1)/($totalParts * $fileSize)
//header("Content-Range: bytes ".$s); // 设置响应范围(字节范围)和总大小(字节数)
readfile($partFile); // 读取并发送当前片段内容给访问者
//unlink($partFile); // 删除已发送的片段文件(可选)
$currentPart++; // 更新当前片段索引
}
这里有插件,可以直接用