返回
如何利用已有的开源库实现文件的上传、分片上传, 文件拼接、下载
前端
2023-09-07 19:20:40
在现代互联网应用中,文件上传是一个常见的需求。随着文件尺寸的不断增大,如何高效地上传大文件成为一个挑战。为了解决这个问题,出现了分片上传技术。分片上传将大文件分割成多个较小的片段,然后逐个上传这些片段。这样可以大大提高上传速度,并降低由于网络故障导致的上传失败的风险。
在本文中,我们将介绍如何使用开源库Easy File Uploader实现文件的上传、分片上传、断点续传和文件下载。Easy File Uploader是一个流行的前端文件上传库,它提供了多种实用的功能,包括分片上传、断点续传和文件拖放。
前端文件上传
// 创建一个Easy File Uploader实例
const uploader = new EasyFileUploader({
// 上传的地址
url: '/upload',
// 选择文件的元素
input: '#file-input',
// 是否开启分片上传
chunked: true,
// 分片大小(默认1MB)
chunkSize: 1024 * 1024,
// 并发上传数(默认1)
concurrent: 1,
// 自定义上传请求头
headers: {
'Authorization': 'Bearer <%= token %>'
},
// 自定义上传请求参数
params: {
'user_id': <%= user_id %>
},
// 上传成功后的回调函数
onSuccess: function(file, response) {
console.log('文件上传成功', response);
},
// 上传失败后的回调函数
onError: function(file, error) {
console.log('文件上传失败', error);
},
// 上传进度更新的回调函数
onProgress: function(file, progress) {
console.log('文件上传进度', progress);
},
});
// 触发文件选择器
uploader.trigger();
后端文件分片上传
// 获取上传的文件
$file = $_FILES['file'];
// 检查文件是否分片上传
if (isset($file['chunks'])) {
// 分片上传
$chunk = (int)$file['chunk'];
$chunks = (int)$file['chunks'];
$name = $file['name'];
// 创建临时文件夹
$tmp_dir = sys_get_temp_dir() . '/uploads/';
if (!file_exists($tmp_dir)) {
mkdir($tmp_dir, 0777, true);
}
// 保存分片文件
$tmp_file = $tmp_dir . $name . '_' . $chunk;
move_uploaded_file($file['tmp_name'], $tmp_file);
// 检查是否所有分片都已上传
if ($chunk == $chunks - 1) {
// 合并分片文件
$final_file = fopen($tmp_dir . $name, 'wb');
for ($i = 0; $i < $chunks; $i++) {
$tmp_file = $tmp_dir . $name . '_' . $i;
$chunk_file = fopen($tmp_file, 'rb');
stream_copy_to_stream($chunk_file, $final_file);
fclose($chunk_file);
unlink($tmp_file);
}
fclose($final_file);
// 移动文件到指定目录
rename($tmp_dir . $name, 'uploads/' . $name);
}
} else {
// 普通上传
// 移动文件到指定目录
move_uploaded_file($file['tmp_name'], 'uploads/' . $file['name']);
}
文件拼接
// 获取所有分片文件
$files = glob('tmp/*');
// 排序分片文件
usort($files, function($a, $b) {
return strnatcmp(basename($a), basename($b));
});
// 创建临时文件
$tmp_file = fopen('tmp/final_file', 'wb');
// 合并分片文件
foreach ($files as $file) {
$chunk_file = fopen($file, 'rb');
stream_copy_to_stream($chunk_file, $tmp_file);
fclose($chunk_file);
unlink($file);
}
// 关闭临时文件
fclose($tmp_file);
// 移动文件到指定目录
rename('tmp/final_file', 'uploads/final_file');
文件下载
// 获取要下载的文件名
$file_name = $_GET['file_name'];
// 检查文件是否存在
if (!file_exists('uploads/' . $file_name)) {
header('HTTP/1.1 404 Not Found');
exit;
}
// 设置下载头
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename=' . $file_name);
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize('uploads/' . $file_name));
// 读取文件内容并输出
readfile('uploads/' . $file_name);