使用io.Pipe()在Golang中读写方式下载zip文件。

huangapple go评论82阅读模式
英文:

Download a zip file using io.Pipe() read/write golang

问题

我正在尝试使用golang中的io.Pipe()函数流式传输zip文件的字节。我正在使用管道读取器(pipe reader)读取zip中每个文件的字节,然后将其流式传输并使用管道写入器(pipe writer)将字节写入响应对象。

这不是一个可工作的实现,而是我尝试实现的结构。我不想使用ioutil.ReadAll,因为文件可能非常大,而使用Pipe()可以避免将所有数据加载到内存中。有人可以帮助我使用io.Pipe()实现一个可工作的实例吗?

英文:

I am trying to stream out bytes of a zip file using io.Pipe() function in golang. I am using pipe reader to read the bytes of each file in the zip and then stream those out and use the pipe writer to write the bytes in the response object.

func main() {
  r, w := io.Pipe()
 // go routine to make the write/read non-blocking
  go func() {
    
    defer w.Close()

    bytes, err := ReadBytesforEachFileFromTheZip() 
    err := json.NewEncoder(w).Encode(bytes)
    handleErr(err)
  }()

This is not a working implementation but a structure of what I am trying to achieve. I don't want to use ioutil.ReadAll since the file is going to be very large and Pipe() will help me avoid bringing all the data into memory. Can someone help with a working implementation using io.Pipe() ?

答案1

得分: 0

我使用golang的io.Pipe()方法使其工作。PipeWriter将字节按块写入管道,而PipeReader从另一端读取。使用go协程的原因是在同时进行读取操作时具有非阻塞的写入操作。

注意:重要的是关闭管道写入器(w.Close()),以发送EOF到流中,否则它将不会关闭流。

func DownloadZip() ([]byte, error) {
    r, w := io.Pipe()

    defer r.Close()
    defer w.Close()

    zip, err := os.Stat("temp.zip")
    if err != nil {
        return nil, err
    }

    go func() {

        f, err := os.Open(zip.Name())
        if err != nil {
            return

        }

        buf := make([]byte, 1024)
        for {
            chunk, err := f.Read(buf)
            if err != nil && err != io.EOF {
                panic(err)
            }
            if chunk == 0 {
                break
            }

            if _, err := w.Write(buf[:chunk]); err != nil {
                return
            }

        }

        w.Close()
    }()

    body, err := ioutil.ReadAll(r)
    if err != nil {
        return nil, err
    }
    return body, nil

}

如果有其他方法,请告诉我。

英文:

I made it work using golang io.Pipe().The Pipewriter writes byte to the pipe in chunks and the pipeReader reader from the other end. The reason for using a go-routine is to have a non-blocking write operation while simultaneous reads happen form the pipe.

Note: It's important to close the pipe writer (w.Close()) to send EOF on the stream otherwise it will not close the stream.

func DownloadZip() ([]byte, error) {
	r, w := io.Pipe()

	defer r.Close()
	defer w.Close()

	zip, err := os.Stat("temp.zip")
	if err != nil{
		return nil, err
	}

	go func(){

		f, err := os.Open(zip.Name())
		if err != nil {
			return

		}

		buf := make([]byte, 1024)
		for {
			chunk, err := f.Read(buf)
			if err != nil && err != io.EOF {
				panic(err)
			}
			if chunk == 0 {
				break
			}

			if _, err := w.Write(buf[:chunk]); err != nil{
				return
			}

		}

		w.Close()
	}()

	body, err := ioutil.ReadAll(r)
	if err != nil {
		return nil, err
	}
	return body, nil

}

Please let me know if someone has another way of doing it.

huangapple
  • 本文由 发表于 2016年11月11日 03:59:16
  • 转载请务必保留本文链接:https://go.coder-hub.com/40536018.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定