【Go Web】文件传输系统-mulpart实现文件夹的传输

本文介绍了一个使用Go语言实现的文件上传系统,该系统利用net/http和multipart包完成文件从客户端到服务端的上传过程。客户端可以指定上传文件的路径和键值,服务端根据键值创建相应的目录并保存文件。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、背景

通过Gonet/http包和mulpart包设计文件存储系统的服务端和客户端。将上传的文件视为一个对象,客户端赋予它一个键,并上传到服务端。

二、客户端
// @File: upload.go
// @Author: Jason
// @Date: 2022/9/12

package main

import (
   "flag"
   "fmt"
   "io"
   "io/ioutil"
   "log"
   "mime/multipart"
   "net/http"
   "os"
   "path"
   "strings"
)

var (
   dir string
   key string
)

func init() {
   flag.StringVar(&dir, "path", ".", "需要上传的文件路径")
   flag.StringVar(&key, "key", "", "对象的键值")
   flag.Parse()
   if key == "" {
      log.Panicln("the key is empty, you need to use --key to set the key.")
   }
}

func UploadDir(key, dir string) {
   r, w := io.Pipe()
   mp := multipart.NewWriter(w)
   go func() {
      defer func() {
         mp.Close()
         w.Close()
      }()
      for absPath := range getFiles(dir) {
         f, _ := os.Open(path.Join(dir, absPath))
         fmt.Println(absPath, path.Dir(absPath))
         fw, e := mp.CreateFormFile(path.Dir(absPath), absPath)
         failOnErr(e, "fail to create form file")
         io.Copy(fw, f)
         f.Close()
      }
   }()
   client := http.Client{}
   req, e := http.NewRequest(http.MethodPut, "http://localhost:8080/", r)
   req.Header.Set("Content-Type", mp.FormDataContentType())
   req.Header.Set("key", key)
   failOnErr(e, "fail to new a request")
   res, e := client.Do(req)
   failOnErr(e, "fail to do request")
   log.Println(res.Status)
}

func main() {
   UploadDir(key, dir)
}

// getFiles获取文件夹下的全部文件,通过chan迭代器的模式获取。
func getFiles(dir string) <-chan string {
   paths := make(chan string)
   go func() {
      defer close(paths)
      gets(paths, dir)
   }()
   return paths
}

func gets(paths chan string, dir_ string) {
   infos, e := ioutil.ReadDir(dir_)
   failOnErr(e, "")
   for _, info := range infos {
      subPath := path.Join(dir_, info.Name())
      if info.IsDir() {
         gets(paths, subPath)
      } else {
         abs := strings.Replace(subPath, dir, "", 1)
         paths <- abs[1:]
      }
   }
}

func failOnErr(e error, msg string) {
   if e != nil {
      log.Panicf("err: %v, msg: %s", e, msg)
   }
}
三、服务端

1、客户端的处理函数

// @File: handler.go
// @Author: Jason
// @Date: 2022/9/12

package server

import (
   "fmt"
   "io"
   "log"
   "net/http"
   "os"
   "path"
)

const (
   dataPath = "receive"
)

func SaveDir(w http.ResponseWriter, r *http.Request) {
   e := r.ParseMultipartForm(32 << 4)
   failOnErr(e, "fail parse multipart form")
   form := r.MultipartForm
   fields := form.File
   key := r.Header.Get("key")
   dirPath := path.Join(dataPath, key)
   e = os.Mkdir(dirPath, 0777)
   if os.IsExist(e) {
      w.WriteHeader(http.StatusConflict)
      return
   }
   for k, files := range fields {
      fmt.Println(k)
      if k != "." {
         e = os.Mkdir(path.Join(dirPath, k), 0777)
      }
      failOnErr(e, "fail to create dir!")
      for _, file := range files {
         f, e := file.Open()
         failOnErr(e, "fail to open file!")
         fw, e := os.Create(path.Join(dirPath, k, file.Filename))
         failOnErr(e, "fail to create file "+file.Filename)
         io.Copy(fw, f)
         fw.Close()
         f.Close()
      }
   }
   w.WriteHeader(http.StatusOK)
}

func failOnErr(e error, msg string) {
   if e != nil {
      log.Printf("err: %v, msg: %s\n", e, msg)
   }
}

2、main函数

// @File: main.go
// @Author: Jason
// @Date: 2022/9/12

package main

import (
   "mulFiles/server"
   "net/http"
)

func main() {
   http.HandleFunc("/", server.SaveDir)
   err := http.ListenAndServe(":8080", nil)
   if err != nil {
      panic(err)
   }
}
四、运行结果

1、项目结构
在这里插入图片描述

(1)data:需要传输的文件夹。

(2)receive:接收的文件夹目录。

2、运行

(1)运行服务端的main.go

(2)命令行运行客户端,制定需要上传的文件夹及键值,键值为服务端接收文件夹下的子文件夹。

client> go run .\upload.go --path=..\data\ --key=key_test
goFiles/go01.go goFiles
goFiles/go02.go goFiles
goFiles/subDir/sub01.go goFiles/subDir
goFiles/subDir/sub02.go goFiles/subDir
goFiles/subDir2/sub2.txt goFiles/subDir2
goFiles/subDir2/subsub/subsub.go goFiles/subDir2/subsub
rootData.txt .
txtData/text1.txt txtData
txtData/text2.txt txtData
2022/09/19 10:31:31 200 OK

(3)运行结果
在这里插入图片描述

  • 可以看到,需要传输的data文件夹传输到(服务端的)receive文件夹下,对应的文件夹为指定的键值(key_test)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值