Go并发读写文件、分片写、分片下载文件的实现示例

 更新时间:2024年01月04日 10:34:19   作者:ProblemTerminator  
读写文件在很多项目中都可以用到,本文主要介绍了Go并发读写文件、分片写、分片下载文件的实现示例,具有一定的参考价值,感兴趣的可以了解一下

简单读取

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会变得很大,此法只适用特定条件下的一般做法。

读取&分片写

读取文件流+分片写-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
}

读取文件流+并发分片写

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
}

并发思路有很多种,看你代码怎么写哦,条条大路通罗马!

更好用的Copy方法

要提醒的是,还有一个很不错的方法在io包里,就是io.Copy(),可防止大文件处理时的内存溢出,也可以替换上述主要流程,比如:

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并发、分片下载

基于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函数用来计算每次的并发数,可按自己方式自行指定
	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
}

到此这篇关于Go并发读写文件、分片写、分片下载文件的实现示例的文章就介绍到这了,更多相关Go并发读写、分片写、分片下载内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家! 

相关文章

  • Go 阻塞的实现示例

    Go 阻塞的实现示例

    Go语言提供了多种同步和通信机制,可以用于实现阻塞的效果,本文主要介绍了Go 阻塞的实现示例,具有一定的参考价值,感兴趣的可以了解一下
    2024-05-05
  • Go 每日一库之termtables的使用

    Go 每日一库之termtables的使用

    本文主要介绍了Go 每日一库之termtables的使用,termtables处理表格形式数据的输出。是一个很小巧的工具库。具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-07-07
  • Zed调试Go项目指南

    Zed调试Go项目指南

    本文主要介绍了Zed调试Go项目指南,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2026-06-06
  • golang使用bcrypt包对密码进行加密的方法实现

    golang使用bcrypt包对密码进行加密的方法实现

    本文主要介绍了golang使用bcrypt包对密码进行加密的方法实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-07-07
  • Go语言中的os.Truncate函数用法解读

    Go语言中的os.Truncate函数用法解读

    这篇文章主要介绍了Go语言中的os.Truncate函数用法,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2025-07-07
  • Golang中接收者方法语法糖的使用方法详解

    Golang中接收者方法语法糖的使用方法详解

    这篇文章主要为大家详细介绍了Golang中接收者方法语法糖的使用方法,文中的示例代码讲解详细,具有一定的学习价值,感兴趣的可以了解一下
    2023-05-05
  • Go语言转化php数组的示例代码

    Go语言转化php数组的示例代码

    这篇文章主要为大家详细介绍了Go语言如何实现转化php数组的相关知识,文中的示例代码讲解详细,对我们深入学习GO语言有一定的帮助,需要的可以参考下
    2023-11-11
  • pytorch中的transforms.ToTensor和transforms.Normalize的实现

    pytorch中的transforms.ToTensor和transforms.Normalize的实现

    本文主要介绍了pytorch中的transforms.ToTensor和transforms.Normalize的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-04-04
  • 基于Golang+Vue编写一个手机远程控制电脑的懒人工具

    基于Golang+Vue编写一个手机远程控制电脑的懒人工具

    这篇文章主要为大家详细介绍了如何基于Golang+Vue编写一个手机远程控制电脑的懒人工具,文中的示例代码讲解详细,感兴趣的小伙伴可以了解下
    2024-11-11
  • 基于Go语言实现一个并发端口扫描器

    基于Go语言实现一个并发端口扫描器

    这篇文章主要介绍了如何使用 Go 实现一个并发端口扫描器,通过 Goroutine 并发扫描多个端口,极大地提升端口扫描的效率,本文不仅讲解了如何使用 Go 的并发特性,还涉及了如何处理超时和错误,保证端口扫描的健壮性和效率,需要的朋友可以参考下
    2025-08-08

最新评论