大文件上传&切片上传

大文件上传&切片上传

简历中如何写项目经验&技术

切片上传相关面试题

基础实现流程

实现核心:秒传 断点续传 切片 …… 如何实现的

最基本的视图

加上拖拽

加上拖拽事件。监听drop事件,event.dataTransfer.files文件对象。其他dragenter dragover dragleave事件event.stopPropagation event.preventDefault

文件预览。URL.createObjectUrl

切片上传实现

根据文件内容得到加密文件名。

file->arrayBuffer->加密buffer->buffer.toString

优化点:放到webworker里不会使用js内存

文件切片 blob.slice

并行上传每个分片。优化点:并发管控

node层:核心的2个接口

上传单个切片的接口

合并切片的接口

const express = require('express');
const logger = require('morgan');
const {
       StatusCodes } = require('http-status-codes');
const cors = require('cors');
const fs = require('fs-extra');
const path = require('path');
const PUBLIC_DIR = path.resolve(__dirname, 'public');
const TEMP_DIR = path.resolve(__dirname, 'temp');
const CHUNK_SIZE = 100 * 1024 * 1024;
//存放上传并合并好的文件
fs.ensureDirSync(PUBLIC_DIR);
//存放分片的文件
fs.ensureDirSync(TEMP_DIR);
const app = express();
app.use(logger('dev'));
app.use(cors());
app.use(express.json());
app.use(express.urlencoded({
       extended: true }));
app.use(express.static(path.resolve(__dirname, 'public')));
/**
 * 上传分片
 */
app.post('/upload/:filename', async (req, res, next) => {
      
    //通过路径参数获取文件名
    const {
       filename } = req.params;
    //通过查询参数获取分片名
    const {
       chunkFileName } = req.query;
    //写入文件的起始位置
    const start = isNaN(req.query.start)?0:parseInt(req.query.start,10);
    //创建用户保存此文件的分片的目录
    const chunkDir = path.resolve(TEMP_DIR, filename);
    //分片的文件路径
    const chunkFilePath = path.resolve(chunkDir, chunkFileName);
    //先确定分片目录存在
    await fs.ensureDir(chunkDir);
    //创建此文件的可写流 ,可以指定写入的起始位置
    const ws = fs.createWriteStream(chunkFilePath, {
      start,flags:'a'});
    //后面会实现暂停操作,如果客户端点击了暂停按钮,会取消上传的操作,取消之后会在服务器触发请求择象的
    //aborted事件,关闭可定流
    req.on('aborted', () => {
       ws.close() });
    //使用管道的方式把请求中的请求体流数据写入到文件中
    try {
      
        await pipeStream(req, ws);
        res.json({
       success: true });
    } catch (error) {
      
        next(error);
    }
});

app.get('/merge/:filename', async (req, res, next) => {
      
    //通过路径参数获取文件名
    const {
       filename } = req.params;
    try {
      
        await mergeChunks(filename);
        res.json({
       success: true });
    } catch (error) {
      
        next(error)
    }
});
app.get('/verify/:filename',async (req,res,next)=>{
      
    const {
      filename} = req.params;
    //先获取文件在服务器的路径
    const filePath = path.resolve(PUBLIC_DIR,filename);
    //判断是文件在服务器端是否存在
    const isExist = await fs.pathExists(filePath);
    //如果已经存在了,则直接返回不需要上传了
    if(isExist){
      
        return res.json({
      success:true,needUpload:false});
    }
    const chunksDir = path.resolve(TEMP_DIR,filename);
    const existDir = await fs.pathExists(chunksDir);
    //存放已经上传的分片的对象数组
    let uploadedChunkList =[];
    if(existDir){
      
        //读取临时目录里面的所有的分片对应的文件
        const chunkFileNames = await fs.readdir(chunksDir);
        //读取每个分片文件的文件信息,主要是它的文件大小,表示已经上传的文件的大小
        uploadedChunkList = await Promise.all(chunkFileNames.map(async function(chunkFileName){
      
            const {
      size} = await fs.stat(path.resolve(chunksDir,chunkFileName));
            return {
      chunkFileName,size};
        }));
    }
    //如果没有此文件,则意味着服务器还需要你上传此文件
    //返回,上传尚未完成,但是已经上传了一部分了,我把已经上传的分片名,以及分片的大小给客户端
    //客户端可以只上传分片剩下的数据部就可以了
    res.json({
      success:true,needUpload:true,uploadedChunkList});
});
async function mergeChunks(filename) {
      
    const mergedFilePath = path.resolve(PUBLIC_DIR, filename);
    const chunkDir = path.resolve(TEMP_DIR, filename);
    const chunkFiles = await fs.readdir(chunkDir);
    //对分片按索引进行升序排列
    chunkFiles.sort((a, b) => Number(a.split('-')[1]) - Number(b.split('-')[1]));
    try {
      
        //为了提高性能,我们在这时可以分片并行写入
        const pipes = chunkFiles.map((chunkFile, index) => {
      
            return pipeStream(
                fs.createReadStream(path.resolve(chunkDir, chunkFile), {
       autoClose: true }),
                fs.createWriteStream(mergedFilePath, {
       start: index * CHUNK_SIZE })
            );
        });
        //并发把每个分片的数据写入到目标文件中
        await Promise.all(pipes);
        //删除分片的文件和文件夹
        await fs.rmdir(chunkDir, {
       recursive: true })
        //合并完文件之后可以重新在这里计算合并后的文件的hash值,和文件中的hash值进行对比
        //如果值是一样的,说明肯定内容是对的,没有被修改
    } catch (error) {
      
        next(error)
    }
}
function pipeStream(rs, ws) {
      
    return new Promise((resolve, reject) => {
      
        //把可读流中的数据写入可写流中
        rs.pipe(ws).on('finish', resolve).on('error', reject);
    });
}
app.listen(8080, () => console.log('Sever started on port 8080'));

进度是每个切片的进度

秒传:已经存在就不传了

取消上传:cancelToken

断点续传:用户点了暂停/网络断开的情况。

优化点:

把耗时的操作放到worker里,不要阻塞主进程

let worker=new Worker('./fileCalculate')

worker.postMessage self.on('message')

如果失败重试3次:但是做的是整个失败重试

待考虑问题:

如何确定切片大小?

如何做文件校验?

相关推荐

  1. 文件分块

    2024-01-13 21:12:06       12 阅读
  2. 文件实现

    2024-01-13 21:12:06       5 阅读
  3. 文件的分片和断点

    2024-01-13 21:12:06       17 阅读
  4. 技术点:实现文件

    2024-01-13 21:12:06       39 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-01-13 21:12:06       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-01-13 21:12:06       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-01-13 21:12:06       18 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-01-13 21:12:06       20 阅读

热门阅读

  1. 麒麟系统编写桌面点击可执行文件

    2024-01-13 21:12:06       43 阅读
  2. 作业-去重复统计(2)

    2024-01-13 21:12:06       31 阅读
  3. 三国杀移动版武将台词大全-蜀

    2024-01-13 21:12:06       45 阅读
  4. Linux文件和目录管理命令----chmod命令

    2024-01-13 21:12:06       39 阅读
  5. 补充前端访问静态资源的一个错误

    2024-01-13 21:12:06       42 阅读
  6. 第五章 : Spring cloud 微服务调用-OpenFeign

    2024-01-13 21:12:06       41 阅读
  7. ffmpeg裁剪视频画面

    2024-01-13 21:12:06       41 阅读
  8. 小工具分享:脚本执行工具Executor

    2024-01-13 21:12:06       39 阅读
  9. AcWing 846. 树的重心(dfs)

    2024-01-13 21:12:06       36 阅读
  10. Springboot Jackson 序列化与反序列化配置

    2024-01-13 21:12:06       33 阅读
  11. Vue面试之watch与computed的区别

    2024-01-13 21:12:06       37 阅读
  12. 代码随想录算法训练营29期Day15|LeetCode 102,226,101

    2024-01-13 21:12:06       34 阅读
  13. LVGL 8.x适配嵌入式Linux的Framebuffer

    2024-01-13 21:12:06       34 阅读