文件上传下载系列——如何实现文件秒传

本文涉及的产品
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
简介: 文件上传下载系列——如何实现文件秒传

简介:

       文件秒传是指在文件上传过程中,如果上传的文件已经在服务器中存在,那么服务器会直接将已经存在的文件的信息返回给客户端,而不需要客户端再次上传文件,从而实现文件的秒传。所以,无论任何大小、格式的文件都可以实现秒传。


       文件秒传通常在云存储和文件共享服务中应用广泛。这种技术能够节省用户上传大文件的时间和带宽,提高文件传输的效率和速度。


       例如,百度云盘、阿里云OSS、腾讯云COS等云存储服务都支持文件秒传技术。

核心思想:

       将文件压缩成128位的MD5哈希值,只要修改文件内容,MD5码就会改变,用MD5码来判断是否是同一文件。

       将MD5码存到数据库中,当有文件上传,首先查询MD5码是否重复,如果重复则不需要上传,通过这种形式实现文件的秒传。


MD5是什么?


       MD5是一种信息摘要算法,原理是通过将输入数据分块,并对每个数据块进行填充、迭代压缩和更新哈希值的方式,最终得到一个128位的哈希值。


不可逆性:信息摘要算法对原数据进行了压缩,无法逆向推导出原始数据


唯一性:由于MD5哈希函数的输出长度为128位,因此总共可以生成2^128个不同的哈希值。(但也是有可能存在哈希碰撞的风险,在一些对安全性要求较高的应用场景下,建议使用更加安全的哈希算法,如SHA-2、SHA-3等)


高效性:MD5算法的设计相对简单,它主要由四个轮函数和一个级联结构组成,这些运算和函数能够快速地对输入数据进行处理,从而提高了算法的执行效率;将输入数据分块,消息块之间的处理是相互独立的,因此可以并行处理,从而提高了处理的效率。

实现步骤:

       文件秒传的实现可以分为以下几个步骤:

  1. 客户端向服务器发送一个上传请求,包含要上传的文件的信息(例如文件名、大小、MD5值等)。
  2. 服务器根据客户端提供的文件信息,查询服务器上是否已经存在相同的文件,如果存在则返回文件已经存在的标识。
  3. 前端接到消息,显示已上传成功。


实操:

1、java生成文件MD5码

       引入的文件

  • java.security.MessageDigest类中有MD5、SHA等加密算法的实现,这里使用其中的MD5算法实现。
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
/**
 * 生成文件的MD5值
 * @param filePath 文件路径
 * @return 文件的MD5值
 */
public static String getFileMD5(String filePath) {
    FileInputStream fis = null;
    try {
        MessageDigest md = MessageDigest.getInstance("MD5");
        fis = new FileInputStream(new File(filePath));
        byte[] buffer = new byte[1024];
        int length;
        while ((length = fis.read(buffer)) != -1) {
            md.update(buffer, 0, length);
        }
        byte[] digest = md.digest();
        StringBuilder sb = new StringBuilder();
        for (byte b : digest) {
            sb.append(String.format("%02x", b & 0xff));
        }
        return sb.toString();
    } catch (NoSuchAlgorithmException | IOException e) {
        e.printStackTrace();
        return null;
    } finally {
        if (fis != null) {
            try {
                fis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

       调用的示例代码:

/**
 * 秒传
 */
public void quickLoad() {
    String filePath = "E:\\DRP.avi"; // 文件路径
    String md5 = getFileMD5(filePath);
    System.out.println(md5); // 输出文件的MD5值
}

       生成的MD5码:

2、javascript生成文件MD5码

function generateFileMD5(file, callback) {
  const reader = new FileReader();
  reader.readAsArrayBuffer(file);
  reader.onload = () => {
    const buffer = reader.result;
    const crypto = window.crypto || window.msCrypto;
    const digestAlgorithm = "MD5";
    const cryptoSubtle = crypto.subtle || crypto.webkitSubtle;
    cryptoSubtle.digest(digestAlgorithm, buffer)
      .then((digest) => {
        const hashArray = Array.from(new Uint8Array(digest));
        const hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
        callback(hashHex);
      })
      .catch((error) => {
        console.error(error);
      });
  };
}

       调用此函数时,需要传入文件对象和回调函数。回调函数将在计算MD5值完成后被调用,并且它将接收计算出的MD5值作为参数。以下是调用该函数的示例代码:

const file = document.getElementById("file-input").files[0]; // 获取文件对象
generateFileMD5(file, (hash) => {
  console.log(hash); // 输出文件的MD5值
});

基于秒传的分片上传下载

       分片上传是指将一个大文件拆分成多个小块进行上传,上传完成后再将小块合并。

上传:

      基于秒传实现分片上传,可以先将文件进行分片并计算出每个分片的MD5值,然后将这些分片和MD5值上传到服务器中存储起来。


       服务器在接收到分片和MD5值后,可以根据MD5值查找Redis中是否已经存在相同的文件。


如果存在,则返回该文件的唯一标识符。对于已上传的分片,服务器将其保存到临时文件夹中,同时记录下该分片的位置信息,这就实现了文件片秒传。

如果不存在,则根据分片的MD5值判断哪些分片已经上传,哪些分片还需要继续上传。对于未上传的分片,服务器返回需要继续上传的分片索引,客户端根据索引上传相应的分片数据。

       当所有分片都上传完成后,服务器将所有分片进行合并,并生成一个唯一的文件标识符,将该标识符和文件信息存储到Redis中。


下载:

       客户端通过文件标识符下载文件时,服务器根据标识符从Redis中获取文件信息,再根据分片位置信息将文件分片进行合并,并返回给客户端。


MD5存储位置

1、持久化到数据库中

优点:方便查找和比较,数据库中的数据不会丢失。

缺点:需要在数据库中创建表以存储MD5值,并确保所有相关文件都已添加到数据库中。

2、存储到redis中

优点:查找速度快,减少网络时延。

缺点:redis的数据存在内存中,数据有丢失的风险,可以设置在开启服务器时自动去数据库取出数据存到redis中。redis存储有限,过多的数据会无法存储,需要综合考量。

总结

       文件秒传的优点在于,对于同一份文件,无论是上传者还是下载者,都可以利用已有的文件块或者整个文件的信息进行操作,不需要重复传输数据,节省了时间和网络资源。这种技术不仅提高了文件上传的效率,也为用户节省了成本,减少了网络带宽的消耗。


       文件秒传也同样存在缺点,首先是安全性问题,如果黑客可以伪造MD5值,则可能存在安全性问题。另外,如果服务器已经存在相同的文件,但是该文件已经损坏或者不完整,秒传可能会导致上传的文件也是不完整的。如果我们选择依赖redis,当Redis出现问题,可能导致秒传失败或者数据丢失。


       总的来说,文件秒传可以带来很多好处,但也存在一些安全性和数据完整性方面的问题需要注意。需要在实现时进行充分的测试和验证,并采取适当的措施保障数据安全和完整性。


       关于文件上传下载设计到的知识点,打算做一个系列进行分享,大家多多评论,感谢阅读!


相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore     ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库 ECS 实例和一台目标数据库 RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
4月前
|
前端开发 API 开发者
Javaweb之前后台分离开发介绍的详细解析
2.1 前后台分离开发介绍 在之前的课程中,我们介绍过,前端开发有2种方式:前后台混合开发和前后台分离开发。 前后台混合开发,顾名思义就是前台后台代码混在一起开发,如下图所示:
53 0
|
3月前
|
存储
fastdfs源码阅读:上传和下载(文件客户端逻辑)
fastdfs源码阅读:上传和下载(文件客户端逻辑)
54 0
|
5月前
项目案例-读写配置文件(C提高)
项目案例-读写配置文件(C提高)
21 0
|
7月前
|
存储 前端开发 C#
如何实现文件断点续传功能
相信大家都使用过迅雷、电驴、百度云网盘等一类的工具,所有这些支持上传或下载的工具都有一个功能,那就是断点续传,也就是在你网络不佳传输断开时,传输会暂停,在网络恢复后,可以继续传输,从而避免数据的重复上传,以减少网络流量,提高效率。那么,你有仔细想过这其中的实现原理嘛?
|
9月前
|
存储 缓存 JSON
php开发实战分析(6):配置文件或缓存文件的生成与调用
php开发实战分析(6):配置文件或缓存文件的生成与调用
104 0
|
前端开发 JavaScript
请问:怎么实现大文件快速上传?
请问:怎么实现大文件快速上传?
145 0
|
前端开发
前端项目实战88-控制只能上传一个文件
前端项目实战88-控制只能上传一个文件
45 0
|
缓存 程序员 应用服务中间件
WEB核心【案例:文件下载,案例:点击切换验证码,几种获取properties资源方式】第十二章
目录1.文件下载1.1超链接下载:1.2自定义servlet下载1.3小结2.点击切换验证码2.1前置只是-验证码生成2.2分析及代码实现2.3需求2:点击切换验证码-绕过缓存3.几种获取preperties资源方式 超链接下载方式自定义Servlet下载通过自定义Servlet 完善超链接下载,可以下载中文名资源
WEB核心【案例:文件下载,案例:点击切换验证码,几种获取properties资源方式】第十二章
|
存储 C语言
【C 语言】文件操作 ( 配置文件读写 | 框架搭建 | 写出或更新配置文件 | 读取配置文件 )
【C 语言】文件操作 ( 配置文件读写 | 框架搭建 | 写出或更新配置文件 | 读取配置文件 )
138 0
|
Java 开发者
如何实现发送带附件的邮件? | 带你读《SpringBoot实战教程》之二十六
本节在之前的案例上增加了怎样实现发送带附件的邮件。
如何实现发送带附件的邮件? | 带你读《SpringBoot实战教程》之二十六