一个简易的Web文件管理器

233 阅读2分钟

最近有空了,把去年做的Web文件管理器项目整理一下,发出来给大伙看看,如果觉得还可以,欢迎Github点赞支持!

预览地址

fm-kv4b.onrender.com/fm/web/logi…

技术栈

  • 后端:NestJS、SQLite
  • 前端:Vue、Element-Plus

特性

  • 断点续传(切片上传)
  • 秒传
  • 上传/下载限速
  • 简单的权限管理

技术实现

断点续传

这部分是在前端部分实现的,利用File API将文件流切成固定大小,然后上传切片,在后端进行拼接和校验文件(通过文件HASH一致性校验)。

断点续传会带来两个问题:1.最后一块切片的大小不固定;2.文件校验的速率;

第一个问题,我是通过切片名称来判断是否为最后一块切片,如果是,则不校验切片大小是否符合预期(通过后续的HASH一致性判断可保证切片没上传错)。

第二个问题,后端通过MD5 HASH来判断一致性,但如果是大文件的话,这个过程会比较漫长(几十秒到几分钟),因此我做了取舍,只校验头尾指定长度的HASH,这样在保证大部分情况文件一致性没问题的同时还能确保效率不下降。同时也校验了最后一个切片是否正确。

秒传

上传文件时存储文件完整的HASH值(在最开始上传时会计算文件的HASH),当上传相同文件时,查询到相同HASH,则认为文件已上传。

上传/下载限速

上传限速由前端控制,由于浏览器限制,无法控制HTTP发送的速率,最后选择了使用Websocket发送文件流的方式来实现。只需要计算好send方法的调用频率即可。

下载限速由后端控制,通过控制文件的ReadStream获取文件流的速度即可,具体代码如下:

  /**
   * 获取待下载文件的可读流
   */
  private getStreamableFile(filePath: string) {
    const downloadBandwidth = this.configService.downloadBandwidth;

    let file: fse.ReadStream;

    if (downloadBandwidth > 0) {
      const onceReadSize = Math.ceil(downloadBandwidth / 10);
      const duration = 100;

      file = fse.createReadStream(filePath, {
        highWaterMark: onceReadSize,
      });

      file.on('readable', async function () {
        if (!file.readableEnded) {
          setTimeout(() => {
            this.read();
          }, duration);
        }
      });
    } else {
      file = fse.createReadStream(filePath);
    }

    return new StreamableFile(file);
  }

最后

感谢观看,欢迎点赞!