最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

golang實現(xiàn)的文件上傳下載小工具

 更新時間:2020年12月22日 12:01:02   作者:janbar  
這篇文章主要介紹了golang實現(xiàn)的文件上傳下載小工具,幫助大家更好的理解和使用python,感興趣的朋友可以了解下

前言

雖然現(xiàn)在文件上傳下載工具多如牛毛,比如http、ftp、sftp、scp等方案都可以用于文件傳輸,但都是需要安裝服務(wù)器甚至客戶端。
有一種場景是我只需要臨時上傳或下載一個文件,完了就不用服務(wù)器運行了,如果使用那些文件傳輸工具,不光安裝麻煩,開啟關(guān)閉也惱火額。
因此才想搞小工具,不過Python愛好者可以用python -m http.server 8080 --bind 192.168.1.100開啟文件服務(wù)器,對我來說還是麻煩。
已經(jīng)上傳到【Github】,隨意鑒賞。

源碼鑒賞

模擬一個http服務(wù)器,通過curl和wget命令作為客戶端實現(xiàn)文件的上傳下載功能。
只是實現(xiàn)一個小工具,所以沒必要使用http庫了,我也試過用http庫來完成相同的功能,發(fā)現(xiàn)很多東西都用不上。
上傳和下載文件加入了進度顯示,方便知道上傳和下載進度。本來想實現(xiàn)斷點續(xù)傳功能,但比較懶,不想弄,原理很簡單。
想想還是把認證授權(quán)加上去,不然太不安全了,命令行更新了使用用戶名和密碼方式的上傳和下載。

package main
 
import (
  "bufio"
  "encoding/base64"
  "errors"
  "fmt"
  "io"
  "net"
  "net/url"
  "os"
  "path/filepath"
  "strconv"
  "strings"
  "unsafe"
)
 
func main() {
  if len(os.Args) != 3 {
    fmt.Printf(`usage: %s ip:port user:pass
 
get file:
 wget --auth-no-challenge --user=user --password=pass --content-disposition "http://ip:port?/home/tmp.txt"
 curl -u user:pass -OJ "http://ip:port?/home/tmp.txt"
post file:
 wget -qO - --auth-no-challenge --user=user --password=pass --post-file=C:\tmp.txt "http://ip:port?/home/tmp.txt"
 curl -u user:pass --data-binary @C:\tmp.txt "http://ip:port?/home/tmp.txt"
`, os.Args[0])
    return
  }
  addr, err := net.ResolveTCPAddr("tcp", os.Args[1])
  if err != nil {
    panic(err)
  }
  ser, err := net.ListenTCP("tcp", addr)
  if err != nil {
    panic(err)
  }
 
  fmt.Printf("Listen: [%s]\n", addr)
  authStr = "Basic " + base64.StdEncoding.EncodeToString([]byte(os.Args[2]))
  for {
    ln, err := ser.AcceptTCP()
    if err != nil {
      panic(err)
    }
    go func(l *net.TCPConn) {
      err := handleFile(l)
      if err != nil {
        respData(l, err.Error())
      }
      l.Close()
    }(ln)
  }
}
 
const (
  maxMemory = 10 << 20 // 緩存10MB
  respMsg  = "HTTP/1.1 200 OK\r\nContent-Type:text/plain;charset=utf-8\r\nContent-Disposition:attachment;filename=resp.txt\r\nContent-Length:%d\r\n\r\n%s"
  getHeader = "HTTP/1.1 200 OK\r\nContent-Type:application/octet-stream\r\nContent-Disposition:attachment;filename=%s\r\nContent-Length:%d\r\nContent-Transfer-Encoding:binary\r\n\r\n"
)
 
var authStr string // 授權(quán)信息
 
func respData(w io.Writer, data string) {
  msg := data + "\r\n"
  fmt.Fprintf(w, respMsg, len(msg), msg)
}
 
func handleFile(l *net.TCPConn) error {
  br := bufio.NewReaderSize(l, maxMemory)
  method, path, length, err := getHeaderMsg(br)
  if err != nil {
    return err
  }
  fmt.Printf("[%s - %s - %d]\n", method, path, length)
 
  if method == "GET" {
    return httpGetFile(path, l, length)
  }
  err = httpPostFile(path, br, length)
  if err != nil {
    return err
  }
  respData(l, "post ok")
  return nil
}
 
// 內(nèi)存復用,更快速,省內(nèi)存
func bytesToString(b []byte) string {
  return *(*string)(unsafe.Pointer(&b))
}
 
func getHeaderMsg(r *bufio.Reader) (string, string, int64, error) {
  // 讀取第一行,提取有用信息
  line, _, err := r.ReadLine()
  if err != nil {
    return "", "", 0, err
  }
  header := strings.Fields(bytesToString(line))
  if len(header) < 3 { // 首行至少3列數(shù)據(jù)
    return "", "", 0, errors.New("header error")
  }
  method, path := header[0], ""
 
  s := strings.Index(header[1], "?")
  if s >= 0 {
    path, _ = url.QueryUnescape(header[1][s+1:])
  }
  if path == "" { // ?號后面就是文件路徑,需要解碼url一下
    return "", "", 0, errors.New("path error")
  }
 
  var length int64
  if method == "GET" {
    fi, err := os.Stat(path)
    if err != nil {
      return "", "", 0, err
    }
    length = fi.Size() // GET請求提前得到文件大小
  } else if method != "POST" {
    return "", "", 0, errors.New(method + " not support")
  }
 
  var authCheck string
  for {
    line, _, err = r.ReadLine()
    if err != nil {
      return "", "", 0, err
    }
    if len(line) == 0 {
      break // 遇到空行,之后為請求體
    }
    header = strings.Split(bytesToString(line), ":")
    if len(header) == 2 { // 頭部[key: val]解析
      header[0] = strings.ToLower(strings.TrimSpace(header[0]))
      header[1] = strings.TrimSpace(header[1])
      if method == "POST" && header[0] == "content-length" {
        length, _ = strconv.ParseInt(header[1], 10, 64)
      } else if header[0] == "authorization" {
        authCheck = header[1]
      }
    }
  }
  if authCheck != authStr {
    return "", "", 0, errors.New("authorization error")
  }
  return method, path, length, nil
}
 
func httpPostFile(path string, r io.Reader, length int64) error {
  fw, err := os.Create(path)
  if err != nil {
    return err
  }
  defer fw.Close()
  pr := newProgress(r, length)
  _, err = io.CopyN(fw, pr, length)
  pr.Close()
  return err
}
 
func httpGetFile(path string, w io.Writer, size int64) error {
  fr, err := os.Open(path)
  if err != nil {
    return err
  }
  defer fr.Close()
  fmt.Fprintf(w, getHeader, filepath.Base(path), size)
  pr := newProgress(fr, size)
  _, err = io.Copy(w, pr)
  pr.Close()
  return err
}
 
type progress struct {
  r  io.Reader
  cnt int64
  rate chan int64
}
 
func newProgress(r io.Reader, size int64) io.ReadCloser {
  p := &progress{r: r, rate: make(chan int64)}
  // 之所以這樣做進度,是因為打印耗性能,因此在協(xié)程中打印進度
  // 在處理數(shù)據(jù)中用非阻塞方式往chan中傳處理字節(jié)數(shù)
  go func(rate <-chan int64, all int64) {
    for cur := range rate {
      fmt.Printf("\rhandle:%4d%%", cur*100/all)
    }
    fmt.Printf("\rhandle: 100%%\r\n\r\n")
  }(p.rate, size)
  return p
}
 
func (p *progress) Read(b []byte) (int, error) {
  n, err := p.r.Read(b)
  p.cnt += int64(n)
  select { // 非阻塞方式往chan中寫數(shù)據(jù)
  case p.rate <- p.cnt:
  default:
  }
  return n, err
}
 
func (p *progress) Close() error {
  close(p.rate) // 關(guān)閉chan,通知打印協(xié)程退出
  return nil
}

食用方法

執(zhí)行UpDownFile-h可以查看幫助文檔,里面有wget和curl上傳和下載文件的命令,方便忘記命令的時候copy一下下。
工具雖小,但確實解決了我個人的臨時上傳下載文件需求,再也不用到處安裝各種服務(wù)器咯,爽爽噠。

usage: UpDownFile ip:port
 
get file:
 wget --auth-no-challenge --user=user --password=pass --content-disposition "http://ip:port?/home/tmp.txt"
 curl -u user:pass -OJ "http://ip:port?/home/tmp.txt"
post file:
 wget -qO - --auth-no-challenge --user=user --password=pass --post-file=C:\tmp.txt "http://ip:port?/home/tmp.txt"
 curl -u user:pass --data-binary @C:\tmp.txt "http://ip:port?/home/tmp.txt"

以上就是golang實現(xiàn)的文件上傳下載小工具的詳細內(nèi)容,更多關(guān)于golang實現(xiàn)文件上傳下載的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Golang實現(xiàn)WebSocket服務(wù)的項目實踐

    Golang實現(xiàn)WebSocket服務(wù)的項目實踐

    本文介紹如何使用Golang實現(xiàn)實時后端WebSocket服務(wù),首先使用Gin框架搭建http服務(wù),然后使用gorilla/websocket庫實現(xiàn)簡單后端WebSocket服務(wù),具有一定的參考價值,感興趣的可以了解一下
    2023-05-05
  • 深入探索Go語言中的高效數(shù)據(jù)結(jié)構(gòu)堆

    深入探索Go語言中的高效數(shù)據(jù)結(jié)構(gòu)堆

    堆,作為一種基本的數(shù)據(jù)結(jié)構(gòu),以其在優(yōu)先隊列和排序算法中提供高效解決方案的能力而聞名。在本文中,我們將深入探討堆的內(nèi)部工作原理,包括其特性、實現(xiàn)細節(jié)以及在現(xiàn)代編程中的應(yīng)用
    2008-06-06
  • Golang內(nèi)存分配機制詳解

    Golang內(nèi)存分配機制詳解

    Go 語言的內(nèi)存分配機制是理解和優(yōu)化 Go 程序性能的關(guān)鍵,在 Go 中,內(nèi)存管理是自動進行的,這得益于 Go 的垃圾回收機制,了解內(nèi)存如何分配和回收,可以幫助我們寫出更高性能的代碼,本文將深入講解下 Go 內(nèi)存分配機制,需要的朋友可以參考下
    2023-12-12
  • Golang并發(fā)發(fā)送HTTP請求的各種方法

    Golang并發(fā)發(fā)送HTTP請求的各種方法

    在 Golang 領(lǐng)域,并發(fā)發(fā)送 HTTP 請求是優(yōu)化 Web 應(yīng)用程序的一項重要技能,本文探討了實現(xiàn)此目的的各種方法,從基本的 goroutine 到涉及通道和sync.WaitGroup 的高級技術(shù),需要的朋友可以參考下
    2024-02-02
  • 四種Golang實現(xiàn)middleware框架的方式小結(jié)

    四種Golang實現(xiàn)middleware框架的方式小結(jié)

    middleware是一般框架里面常用的形式,比如web框架、rpc框架等,本文為大家詳細介紹了四種實現(xiàn)middleawre的方式,感興趣的可以了解一下
    2024-03-03
  • Golang常用的幾種密碼加密方式分享

    Golang常用的幾種密碼加密方式分享

    這篇文章給大家介紹了Golang常用的幾種密碼加密方式,加密有兩種方式,一種是直接加密,一種是鹽值加密,直接加密指的是將原始密碼直接進行加密,鹽值加密則是在進行密碼加密之前,文中有詳細的代碼示例,需要的朋友可以參考下
    2023-08-08
  • Go語言協(xié)程通道使用的問題小結(jié)

    Go語言協(xié)程通道使用的問題小結(jié)

    本文主要介紹了Go語言協(xié)程通道使用的問題小結(jié),詳細的介紹了使用的一些重要問題,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2024-08-08
  • Golang標準庫time包日常用法小結(jié)

    Golang標準庫time包日常用法小結(jié)

    本文主要介紹了Golang標準庫time包日常用法小結(jié),可以通過它們來獲取當前時間、創(chuàng)建指定時間、解析時間字符串、控制時間間隔等操作,感興趣的可以了解一下
    2023-11-11
  • go 生成器模式的具體使用

    go 生成器模式的具體使用

    生成器是一種創(chuàng)建型設(shè)計模式,使你能夠分步驟創(chuàng)建復雜對象,本文主要介紹了go生成器模式的具體使用,具有一定的參考價值,感興趣的可以了解一下
    2024-01-01
  • 在Go語言項目中使用Zap日志庫的操作過程

    在Go語言項目中使用Zap日志庫的操作過程

    本文將先介紹Go語言原生的日志庫的使用,然后詳細介紹非常流行的Uber開源的zap日志庫,同時會介紹如何搭配·Lumberjack·實現(xiàn)日志的切割和歸檔,對Go使用Zap日志庫相關(guān)知識感興趣的朋友一起看看吧
    2024-03-03

最新評論

巴马| 玉树县| 宝应县| 青阳县| 梧州市| 松原市| 山东省| 曲周县| 奇台县| 和平区| 九龙城区| 图木舒克市| 安乡县| 南部县| 阿坝县| 湾仔区| 郁南县| 犍为县| 潜山县| 呼和浩特市| 昆山市| 和田县| 博客| 海兴县| 龙州县| 湘乡市| 林州市| 忻城县| 中方县| 连山| 通城县| 龙南县| 长岭县| 云浮市| 唐海县| 洛扎县| 宜兴市| 邻水| 航空| 临安市| 嘉禾县|