douaoren4402 2016-11-10 19:59
浏览 543
已采纳

使用io.Pipe()读取/写入golang下载zip文件

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条回答 默认 最新

  • dongnao2048 2016-11-11 22:12
    关注

    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.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?