写这篇文章就是为了养成良好习惯,将最近的一些学习记录下来,防止忘记,好记性不如烂笔头。
这里我使用的files.slice 方法来完成分片,使用npm i crc库计算crc32值。
let files = file
//切片大小 10kb
const chunkSize = 1024 * 1024 * 2;
let currentChunk = 0;
let indexChunk = 1;
//切片数组
const chunkList = [];
// 创建一个FileReader对象,用于读取文件
const fileR = new FileReader();
// 读取文件作为ArrayBuffer
fileR.readAsArrayBuffer(files);
fileR.onload = function(e) {
let file = e.target.result;
// 当文件读取完成后,计算原始文件文件的crc32校验值
files.crc32 = crc32(file).toString(16);
console.log(files.crc32);
};
while (currentChunk < files.size) {
let chunk = files.slice(currentChunk, currentChunk + chunkSize);
// 将片段转换为ArrayBuffer,然后计算片段的crc32校验值
await chunk.arrayBuffer().then(res => {
//切边数组组装(切片大小,原始大小,切片crc32值,切片文件名)
let formData = {
file: chunk,
size: chunk.size,
fileName: files.name,
chunkName: `${files.name}_${indexChunk}`,
crc32: crc32(res).toString(16)
};
chunkList.push(formData);
});
currentChunk += chunkSize;
indexChunk += 1;
}
这里我使用 express 完成了一个简单的后端保存切片合并切片,以及检查文件是否上传过。前端切片总体来说是一个比较简单的小功能,这里我没有对流程做任何优化,后端也没有对文件进行校验。所以简单的小功能做好也要花一番心思。我想说的就这么多了。
//合并
app.post("/merge", multi,(req, res) => {
try {
const { oldCrc32 ,fileName } = req.body;
console.log("merge");
//打开临时文件夹
let Directory = path.join(__dirname, "/upload/", oldCrc32);
//合并后文件存放位置
let filePath = path.join(__dirname, "/upload/", fileName);
//读取文件列表
fs.readdir(Directory, (err, fileList) => {
if(!err){
let pool = fileList.map(item=>new Promise(resolve=>{
let chunkPath = path.join(Directory, item);
//将切片文件写入新文件中-合并文件
fs.appendFileSync(filePath,fs.readFileSync(chunkPath));
resolve()
}));
Promise.all(pool).then(()=>{
fs.rmdirSync(Directory);
res.send({
code: 200,
msg: "成功",
});
})
}
});
}catch{
console.log("失败")
}
});
// 上传
app.post("/upload", multi, (req, res) => {
const { file, ...data } = req.body;
console.log("upload", req.files);
try {
// 使用总文件crc32值作为临时文件夹名称
let Directory = path.join(__dirname, "/upload/", data.oldCrc32);
fs.stat(Directory, (err, stats) => {
// 判断该文件是否有过上传
if (!stats) {
//没有则直接创建文件夹并上传
fs.mkdir(Directory, (err) => {
if (err) {
console.log("失败" + err);
} else {
let fileName = path.join(Directory, data.chunkName);
const files = fs.readFileSync(req.files.file.path);
fs.writeFile(fileName, files, (err) => {
if (err) {
console.log("失败" + err);
} else {
res.send({
code: 200,
msg: "成功",
});
}
});
}
});
} else {
//有则查询该切片是否被上传过
let fileName = path.join(Directory, data.chunkName);
fs.stat(fileName, (err, stats) => {
if (!stats) {
//该切片未被上传过
const files = fs.readFileSync(req.files.file.path);
fs.writeFile(fileName, files, (err) => {
if (err) {
console.log("失败" + err);
} else {
res.send({
code: 200,
msg: "成功",
});
}
});
} else {
//该切片已经被上传过
res.send({
code: 200,
msg: "文件存在",
});
// let crc = crc32(file.file);
}
});
}
});
} catch (err) {
console.log("失败" + err);
}
});
//检查
app.post("/verify", multi, (req, res) => {
try {
const { file, ...data } = req.body;
console.log("verify", req.files);
let Directory = path.join(__dirname, "/upload/", data.oldCrc32);
fs.stat(Directory, (err, stats) => {
// 检查文件夹是否存在
if (!stats) {
res.send({
code: 200,
msg: "成功",
});
} else {
let fileName = path.join(Directory, data.chunkName);
fs.stat(fileName, (err, stats) => {
//检查文件是否上传过
if (!stats) {
res.send({
code: 200,
msg: "失败",
});
} else {
//文件已经上传过
res.send({
code: 200,
msg: "文件存在",
});
}
});
}
});
} catch {}
});