侯体宗的博客
  • 首页
  • Hyperf版
  • beego仿版
  • 人生(杂谈)
  • 技术
  • 关于我
  • 更多分类
    • 文件下载
    • 文字修仙
    • 中国象棋ai
    • 群聊
    • 九宫格抽奖
    • 拼图
    • 消消乐
    • 相册

Golang实现异步上传文件支持进度条查询的方法

Go  /  管理员 发布于 7年前   288

业务背景

业务需求要求开发一个异步上传文件的接口,并支持上传进度的查询。

需求分析

ZIP压缩包中,包含一个csv文件和一个图片文件夹,要求:解析csv数据存入mongo,将图片文件夹中的图片信息对应上csv中的人员信息。

ZIP压缩包解压

使用golang自带的 "archive/zip" 包解压。

func decompressZip(filePath, dest string) (string, string, error) {  var csvName string  imageFolder := path.Base(filePath)  ext := path.Ext(filePath)  folderName := strings.TrimSuffix(imageFolder, ext)  src, err := os.Open(filePath)  if err != nil {    return "", "", err  }  defer src.Close()  zipFile, err := zip.OpenReader(src.Name())  if err != nil {    return "", "", err  }  defer zipFile.Close()  err = os.MkdirAll(path.Join(dest, folderName), os.ModePerm)  for _, innerFile := range zipFile.File {    info := innerFile.FileInfo()    if info.IsDir() {      continue    }    dst, err := os.Create(path.Join(dest, folderName, info.Name()))    if err != nil {      fmt.Println(err.Error())      continue    }    src, err := innerFile.Open()    if err != nil {      fmt.Println(err.Error())      continue    }    io.Copy(dst, src)  }  destPath, err := ioutil.ReadDir(path.Join(dest, folderName))  if err != nil {    return "", "", err  }  for _, v := range destPath {    if path.Ext(v.Name()) == ".csv" {      csvName = path.Join(dest, folderName, v.Name())    }  }  return folderName, csvName, nil}

在这个解压的过程中,压缩包的树结构只能到2层

import.zip┝┅┅import.csv┖┅┅images

在解压后,所有的文件都会在同一个目录下,既images中的图片会变成和.csv文件同级

验证csv文件编码格式是否为UTF-8

func ValidUTF8(buf []byte) bool {  nBytes := 0  for i := 0; i < len(buf); i++ {    if nBytes == 0 {      if (buf[i] & 0x80) != 0 { //与操作之后不为0,说明首位为1        for (buf[i] & 0x80) != 0 {          buf[i] <<= 1 //左移一位          nBytes++   //记录字符共占几个字节        }        if nBytes < 2 || nBytes > 6 { //因为UTF8编码单字符最多不超过6个字节          return false        }        nBytes-- //减掉首字节的一个计数      }    } else { //处理多字节字符      if buf[i]&0xc0 != 0x80 { //判断多字节后面的字节是否是10开头        return false      }      nBytes--    }  }  return nBytes == 0}

后续支持utf-8转码

这个utf8编码判断方法是网上down下来的,后续优化一下

主逻辑

type LineWrong struct {  LineNumber int64 `json:"line_number"`  Msg    string `json:"msg"`}func Import(/*自定义参数*/){  // decompress zip file to destination address  folder, csvName, err := Decompress(path.Join(constant.FolderPrefix, req.FilePath), dest)  if err != nil {    fmt.Println(err.Error())  }  // check if the file encoding is utf8  b, err := ioutil.ReadFile(csvName)  if err != nil {    fmt.Println(err.Error())  }  if !utils.ValidUTF8(b) {    fmt.Println(errors.New("数据编码错误,请使用utf-8格式csv!"))  }  // create goroutine to analysis data into mongodb  var wg sync.WaitGroup  wg.Add(1)  // used to interrupt goroutine  resultChan := make(chan error)  // used to record wrong row in csv  lW := make(chan []LineWrong)  go func(ctx *gin.Context, Name, csvPath, dir, folder string) {    defer wg.Done()    tidT, ciT, lwT, err := importCsv(ctx, Name, csvPath, dir, folder)    resultChan <- err    if err != nil {      fmt.Println(err.Error())    }    lW <- lwT    if len(lwT) == 0 {      importClassData(ctx, tidT, ciT)    }  }(ctx, req.Name, csvName, dest, folder)  err = <-resultChan  lineWrong := <-lW  close(lW)  ・・・}// pre-analysis data in csv and through wrong data with line numbers and informationfunc importCsv()(){  ・・・}// analysis data again and save data into mongodb, if is there any error,through them same as import()func importClassData()(){  ・・・  conn, err := connect()  if err != nil {    return err  }  defer conn.Close()  conn.Do("hset", taskId, "task_id", (curLine*100)/totalLines)  ・・・}

将错误信息以channel接收,使用 package "sync" 的 sync.WaitGroup 控制异步协程。在入库的过程中,将当前的进度存入redis。

查询进度接口

func QueryImport()(){  conn, err := connect()  if err != nil {    return nil, err  }  defer conn.Close()  progress, _ := conn.Do("hget", key, field)  if pro, ok := progress.([]uint8); ok {    ba := []byte{}    for _, b := range pro {      ba = append(ba, byte(b))    }    progress,_ = strconv.Atoi(string(ba))  }  return progress}

从redis中取出来的数据是[]uint8类型数据,先断言,然后转类型返回。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。


  • 上一条:
    golang的空标识符理解
    下一条:
    golang中使用proto3协议导致的空值字段不显示的问题处理方案
  • 昵称:

    邮箱:

    0条评论 (评论内容有缓存机制,请悉知!)
    最新最热
    • 分类目录
    • 人生(杂谈)
    • 技术
    • linux
    • Java
    • php
    • 框架(架构)
    • 前端
    • ThinkPHP
    • 数据库
    • 微信(小程序)
    • Laravel
    • Redis
    • Docker
    • Go
    • swoole
    • Windows
    • Python
    • 苹果(mac/ios)
    • 相关文章
    • 在go中实现一个常用的先进先出的缓存淘汰算法示例代码(0个评论)
    • 在go+gin中使用"github.com/skip2/go-qrcode"实现url转二维码功能(0个评论)
    • 在go语言中使用api.geonames.org接口实现根据国际邮政编码获取地址信息功能(1个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf分页文件功能(0个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf文件功能(0个评论)
    • 近期文章
    • 在go中实现一个常用的先进先出的缓存淘汰算法示例代码(0个评论)
    • 在go+gin中使用"github.com/skip2/go-qrcode"实现url转二维码功能(0个评论)
    • 在go语言中使用api.geonames.org接口实现根据国际邮政编码获取地址信息功能(1个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf分页文件功能(0个评论)
    • gmail发邮件报错:534 5.7.9 Application-specific password required...解决方案(0个评论)
    • 欧盟关于强迫劳动的规定的官方举报渠道及官方举报网站(0个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf文件功能(0个评论)
    • Laravel从Accel获得5700万美元A轮融资(0个评论)
    • 在go + gin中gorm实现指定搜索/区间搜索分页列表功能接口实例(0个评论)
    • 在go语言中实现IP/CIDR的ip和netmask互转及IP段形式互转及ip是否存在IP/CIDR(0个评论)
    • 近期评论
    • 122 在

      学历:一种延缓就业设计,生活需求下的权衡之选中评论 工作几年后,报名考研了,到现在还没认真学习备考,迷茫中。作为一名北漂互联网打工人..
    • 123 在

      Clash for Windows作者删库跑路了,github已404中评论 按理说只要你在国内,所有的流量进出都在监控范围内,不管你怎么隐藏也没用,想搞你分..
    • 原梓番博客 在

      在Laravel框架中使用模型Model分表最简单的方法中评论 好久好久都没看友情链接申请了,今天刚看,已经添加。..
    • 博主 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 @1111老铁这个不行了,可以看看近期评论的其他文章..
    • 1111 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 网站不能打开,博主百忙中能否发个APP下载链接,佛跳墙或极光..
    • 2016-10
    • 2017-09
    • 2020-03
    • 2020-05
    • 2020-06
    • 2020-07
    • 2020-12
    • 2021-01
    • 2021-05
    • 2021-06
    • 2021-07
    • 2021-08
    • 2021-10
    • 2021-11
    • 2021-12
    • 2022-01
    • 2022-02
    • 2022-03
    • 2022-04
    • 2022-05
    • 2022-06
    • 2022-07
    • 2022-08
    • 2022-09
    • 2022-10
    • 2022-11
    • 2022-12
    • 2023-01
    • 2023-02
    • 2023-03
    • 2023-04
    • 2023-05
    • 2023-06
    • 2023-07
    • 2023-08
    • 2023-09
    • 2023-10
    • 2023-11
    • 2023-12
    • 2024-01
    • 2024-02
    • 2024-03
    • 2024-04
    • 2024-05
    • 2024-06
    • 2024-07
    • 2024-08
    • 2024-11
    • 2025-02
    • 2025-04
    • 2025-05
    • 2025-06
    Top

    Copyright·© 2019 侯体宗版权所有· 粤ICP备20027696号 PHP交流群

    侯体宗的博客