使用react+antd实现大文件上传(Vue同理,切换组件即可)
import { Upload, Button, message } from "antd";
import { UploadOutlined } from "@ant-design/icons";
import { useRef, useState } from "react";
import axios from "axios";
import SparkMD5 from "spark-md5";
function calculateMD5(file) {
return new Promise((resolve) => {
const spark = new SparkMD5.ArrayBuffer();
const fileReader = new FileReader();
const chunkSize = 2 * 1024 * 1024;
let currentChunk = 0;
fileReader.onload = function (e) {
spark.append(e.target.result);
currentChunk++;
if (currentChunk < chunks) {
loadNext();
} else {
const result = spark.end();
resolve(result);
}
};
function loadNext() {
const start = currentChunk * chunkSize;
const end = Math.min(file.size, start + chunkSize);
const buffer = file.slice(start, end);
fileReader.readAsArrayBuffer(buffer);
}
const chunks = Math.ceil(file.size / chunkSize);
loadNext();
});
}
function chunkFile(file, chunkSize) {
const chunks = Math.ceil(file.size / chunkSize);
const chunksList = [];
let currentChunk = 0;
while (currentChunk < chunks) {
const start = currentChunk * chunkSize;
const end = Math.min(file.size, start + chunkSize);
const chunk = file.slice(start, end);
chunksList.push(chunk);
currentChunk++;
}
return chunksList;
}
function App() {
const [uploading, setUploading] = useState(false);
const chunkRefs = useRef([]);
const md5Ref = useRef("");
const handleFileChange = async ({ file }) => {
setUploading(true);
const md5 = await calculateMD5(file);
md5Ref.current = md5;
// 将文件分片并保存到 reference 对象中
const chunksList = chunkFile(file, 2 * 1024 * 1024);
chunkRefs.current = chunksList.map((chunk, index) => {
const formData = new FormData();
formData.append("chunk", chunk);
formData.append("filename", file.name);
formData.append("total", chunksList.length);
formData.append("index", index.toString());
return formData;
});
// 上传分片
const uploadPromises = chunkRefs.current.map((formData) =>
axios.post("http://localhost:3000/upload", formData)
);
try {
await Promise.all(uploadPromises);
message.success("文件上传成功!");
} catch (error) {
console.error(error);
message.error("文件上传失败!");
}
setUploading(false);
};
return (
<div>
<Upload
name="file"
accept=".jpg,.jpeg,.png,.gif,.zip,.rar,.pdf,.doc,.docx,.xls,.xlsx,.ppt,.pptx"
multiple={false}
showUploadList={false}
beforeUpload={() => false}
onChange={handleFileChange}
>
<Button loading={uploading} icon={<UploadOutlined />}>
{uploading ? "上传中" : "开始上传"}
</Button>
</Upload>
</div>
);
}
export default App;