欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Go并發(fā)讀寫文件、分片寫、分片下載文件的實(shí)現(xiàn)示例

 更新時(shí)間:2024年01月04日 10:34:19   作者:ProblemTerminator  
讀寫文件在很多項(xiàng)目中都可以用到,本文主要介紹了Go并發(fā)讀寫文件、分片寫、分片下載文件的實(shí)現(xiàn)示例,具有一定的參考價(jià)值,感興趣的可以了解一下

簡單讀取

func ReadFile(filePath string) (chunks []byte, err error) {
	f, err := os.Open(filePath)
	if err != nil {
		return
	}
    
    defer f.Close()
	reader := bufio.NewReader(f)

	for {
		dataByte := make([]byte, 5*1024)
		var n int
		n, err = reader.Read(dataByte)
		if err != nil || 0 == n {
			break
		}

		chunks = append(chunks, dataByte[:n]...)
		fmt.Printf("file: %s, len(chunks):%v", filePath, len(chunks))
	}

	isEOF := strings.Compare(err.Error(), "EOF")
	if isEOF == 0 {
		err = nil
		fmt.Printf("read %s success: \n, len=%v", filePath, len(chunks))
		return
	}

	fmt.Printf("readFile over")
	return
}

可以看到如文件較大,chunks會(huì)變得很大,此法只適用特定條件下的一般做法。

讀取&分片寫

讀取文件流+分片寫-1

var bufLen = 2 * 1024 * 1024

func DownLoadFileShardByFilePath1(writerFilePath string, body io.Reader) (err error) {

	f, err := os.OpenFile(writerFilePath, os.O_CREATE|os.O_APPEND|os.O_WRONLY, os.ModeAppend)
	defer f.Close()
	if err != nil {
		fmt.Println("open err:" + err.Error())
		return
	}

	writer := bufio.NewWriter(f)
	bs := make([]byte, bufLen)
	for {
		var read int
		read, err = body.Read(bs)
		if err != nil || 0 == read {
			break
		}

		_, err = writer.Write(bs[:read])
		if err != nil {
			fmt.Println("write err:" + err.Error())
			break
		}
	}

	if err == io.EOF {
		err = nil
	}

	if err != nil {
		return
	}

	if err = writer.Flush(); err != nil {
		fmt.Println("writer flush err: ", err.Error())
		return
	}

	fmt.Printf("downLoad over")
	return
}

讀取文件流+分片寫-2

var bufLen = 2 * 1024 * 1024

func DownLoadFileShard(writerFilePath string, body io.Reader) (err error) {

	f, err := os.OpenFile(writerFilePath, os.O_CREATE|os.O_APPEND|os.O_WRONLY, os.ModeAppend)
	if err != nil {
		fmt.Println("open err:" + err.Error())
		return
	}

    defer f.Close()
	bs := make([]byte, bufLen)
	writer := bufio.NewWriter(f)
	for {
		var read int
		switch read, err = body.Read(bs[:]); true {
		case read < 0:
			fmt.Println("read err: ", err.Error())
			return
		case read == 0, err == io.EOF:
			fmt.Printf("downLoad over")
			return writer.Flush()
		case read > 0:
			_, err = writer.Write(bs[:read])
			if err != nil {
				fmt.Println("write err:" + err.Error())
				return
			}
		}
	}

	return
}

讀取文件流+并發(fā)分片寫

type FileShard struct {
	Data []byte
	Err  error
	Code int // 0-正常  -1=失敗
}

var bufLen = 2 * 1024 * 1024

func DownLoadFileShardCon(writerFilePath string, body io.Reader) (err error) {

	writerFile, err := os.OpenFile(writerFilePath, os.O_CREATE|os.O_APPEND|os.O_WRONLY, os.ModeAppend)
	if err != nil {
		fmt.Println("open err:" + err.Error())
		return
	}

    defer writerFile.Close()
	ch, complete := make(chan *FileShard), make(chan struct{})
	go func() {
		writer := bufio.NewWriter(writerFile)

	youKnow:
		for {
			select {
			case data := <-ch:
				if data == nil {
					err = writer.Flush()
					break youKnow
				}

				if data.Code != 0 {
					err = data.Err
					break youKnow
				}

				if _, err = writer.Write(data.Data); err != nil {
					fmt.Println("write err:", err.Error())
				}
			}
		}

		close(complete)
	}()

	go func() {
		bs := make([]byte, bufLen)
		for {
			switch read, readErr := body.Read(bs[:]); true {
			case read < 0:
				ch <- &FileShard{Code: -1, Err: readErr}
				close(ch)
				return
			case read == 0, err == io.EOF:
				close(ch)
				return
			case read > 0:
				ch <- &FileShard{Data: bs[:read], Code: 0}
			}
		}

	}()

	select {
	case <-complete:
		break
	}

	fmt.Printf("downLoad over")
	return
}

并發(fā)思路有很多種,看你代碼怎么寫哦,條條大路通羅馬!

更好用的Copy方法

要提醒的是,還有一個(gè)很不錯(cuò)的方法在io包里,就是io.Copy(),可防止大文件處理時(shí)的內(nèi)存溢出,也可以替換上述主要流程,比如:

func IOCopyExample(writerFilePath string, body io.Reader) (err error) {
	f, err := os.OpenFile(writerFilePath, os.O_CREATE|os.O_TRUNC, 0666)
	if err != nil {
		return
	}
	
	defer f.Close()
	writer := bufio.NewWriter(f)
	_, err = io.Copy(writer, body)
	_ = writer.Flush()
	return
}

http并發(fā)、分片下載

基于http的Range來完成:

func DownloadFileRange(url, writeFile string) error {
	f, err := os.OpenFile(writeFile , os.O_CREATE|os.O_TRUNC, 0666)
	if err != nil {
		return err
	}

	defer f.Close()

	resp, err := http.Head(url)
	if err != nil {
		return err
	}

	size, err := strconv.Atoi(resp.Header.Get("Content-Length"))
	if err != nil {
		return err
	}

	con := getSize(size)  // getSize函數(shù)用來計(jì)算每次的并發(fā)數(shù),可按自己方式自行指定
	var start, end int64
	for i := 0; i < con; i++ {
		
		start = int64(i) * int64(size/con)
		end = start + int64(size/con) - 1

		go func(n int, offset, end int64) {
			req := &http.Request{}
			req, err = http.NewRequest(http.MethodGet, url, nil)
			req.Header.Set("Range", fmt.Sprintf("bytes=%v-%v", offset, end))

			client := &http.Client{}
			resp, err = client.Do(req)
			if err != nil {
				return
			}

			defer resp.Body.Close()

			f.Seek(offset, 0)
			_, err = io.Copy(f, resp.Body)
			if err != nil {
				// log
			}

		}(i, start, end)
	}

	return nil
}

到此這篇關(guān)于Go并發(fā)讀寫文件、分片寫、分片下載文件的實(shí)現(xiàn)示例的文章就介紹到這了,更多相關(guān)Go并發(fā)讀寫、分片寫、分片下載內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家! 

相關(guān)文章

  • golang bad file descriptor問題的解決方法

    golang bad file descriptor問題的解決方法

    這篇文章主要給大家介紹了golang bad file descriptor問題的解決方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-02-02
  • Go 修改map slice array元素值操作

    Go 修改map slice array元素值操作

    這篇文章主要介紹了Go 修改map slice array元素值操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2020-12-12
  • Golang程序如何查找內(nèi)存泄漏(pprof)

    Golang程序如何查找內(nèi)存泄漏(pprof)

    該文章詳細(xì)介紹了如何使用Golang的pprof工具查找內(nèi)存泄漏,首先,在main包中引入pprof包并設(shè)置條件編譯,然后編譯程序并運(yùn)行,通過執(zhí)行g(shù)otoolpprof-inuse_space命令,可以進(jìn)入交互模式并使用top命令查看內(nèi)存分配最多的函數(shù),如果本機(jī)中有源代碼
    2024-12-12
  • golang內(nèi)存對(duì)齊的項(xiàng)目實(shí)踐

    golang內(nèi)存對(duì)齊的項(xiàng)目實(shí)踐

    本文主要介紹了golang內(nèi)存對(duì)齊的項(xiàng)目實(shí)踐,內(nèi)存對(duì)齊不僅有助于提高內(nèi)存訪問效率,還確保了與硬件接口的兼容性,是Go語言編程中不可忽視的重要優(yōu)化手段,下面就來介紹一下
    2025-02-02
  • 使用go實(shí)現(xiàn)簡易比特幣區(qū)塊鏈公鏈功能

    使用go實(shí)現(xiàn)簡易比特幣區(qū)塊鏈公鏈功能

    這篇文章主要介紹了使用go實(shí)現(xiàn)簡易比特幣區(qū)塊鏈公鏈功能,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-01-01
  • Golang中interface{}轉(zhuǎn)為數(shù)組的操作

    Golang中interface{}轉(zhuǎn)為數(shù)組的操作

    這篇文章主要介紹了Golang中interface{}轉(zhuǎn)為數(shù)組的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2021-04-04
  • GoLang中拼接字符串性能優(yōu)化方法詳解

    GoLang中拼接字符串性能優(yōu)化方法詳解

    最近在做性能優(yōu)化,有個(gè)函數(shù)里面的耗時(shí)特別長,看里面的操作大多是一些字符串拼接的操作,而字符串拼接在 golang 里面其實(shí)有很多種實(shí)現(xiàn),下面這篇文章主要給大家介紹了關(guān)于Golang語言如何高效拼接字符串的相關(guān)資料,需要的朋友可以參考下
    2023-02-02
  • 深入理解 Go 語言中的 Context

    深入理解 Go 語言中的 Context

    這篇文章主要介紹了 理解 Go 語言中的 Context,需要的朋友可以參考下
    2020-06-06
  • Go實(shí)現(xiàn)數(shù)據(jù)脫敏的方案設(shè)計(jì)

    Go實(shí)現(xiàn)數(shù)據(jù)脫敏的方案設(shè)計(jì)

    在一些常見的業(yè)務(wù)場景中可能涉及到用戶的手機(jī)號(hào),銀行卡號(hào)等敏感數(shù)據(jù),對(duì)于這部分的數(shù)據(jù)經(jīng)常需要進(jìn)行數(shù)據(jù)脫敏處理,就是將此部分?jǐn)?shù)據(jù)隱私化,防止數(shù)據(jù)泄露,所以本文給大家介紹了Go實(shí)現(xiàn)數(shù)據(jù)脫敏的方案設(shè)計(jì),需要的朋友可以參考下
    2024-05-05
  • Go語言實(shí)現(xiàn)字符串切片賦值的方法小結(jié)

    Go語言實(shí)現(xiàn)字符串切片賦值的方法小結(jié)

    這篇文章主要給大家介紹了Go語言實(shí)現(xiàn)字符串切片賦值的兩種方法,分別是在for循環(huán)的range中以及在函數(shù)的參數(shù)傳遞中實(shí)現(xiàn),有需要的朋友們可以根據(jù)自己的需要選擇使用。下面來一起看看吧。
    2016-10-10

最新評(píng)論