使用io.Pipe()读/写golang下载zip文件
我正在尝试使用golang中的io.Pipe()函数从zip文件中输出字节。我正在使用管道读取器读取zip中每个文件的字节,然后将这些字节流出来,并使用管道写入器在响应对象中写入字节使用io.Pipe()读/写golang下载zip文件,go,zip,pipe,streamreader,writer,Go,Zip,Pipe,Streamreader,Writer,我正在尝试使用golang中的io.Pipe()函数从zip文件中输出字节。我正在使用管道读取器读取zip中每个文件的字节,然后将这些字节流出来,并使用管道写入器在响应对象中写入字节 func main() { r, w := io.Pipe() // go routine to make the write/read non-blocking go func() { defer w.Close() bytes, err := ReadBytesforEachFil
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)
}()
这不是一个有效的实现,而是我试图实现的结构。我不想使用ioutil.ReadAll,因为文件将非常大,Pipe()将帮助我避免将所有数据带入内存。有人能用io.Pipe()帮助实现吗?我用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
}
如果有人有其他方法,请告诉我。我使用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
}
如果有人有其他方法,请告诉我。您需要阅读整个文件
zip.NewReader
接受一个io.ReaderAt
,这是管道无法实现的。无法使用io.Copy(zipReader,w)@mh cbon我不是100%确定,但没有io。复制是否在下面使用缓冲区?我想避免这种情况。@JimB难道没有办法避免读取整个zip文件吗?我确信当zip文件的大小很大时,没有人想把所有的数据都放到内存中。以块的形式读取字节怎么样?奇怪的是,如果它是一个常规目录,我可以使用管道吗?@psbits:zip格式就是这样工作的。中心目录位于文件末尾,因此如果不先查找文件末尾并读取目录,就无法(轻松或正确地)提取文件。您需要读取整个文件zip.NewReader
接受一个io.ReaderAt
,这是管道无法实现的。无法使用io.Copy(zipReader,w)@mh cbon我不是100%确定,但没有io。复制是否在下面使用缓冲区?我想避免这种情况。@JimB难道没有办法避免读取整个zip文件吗?我确信当zip文件的大小很大时,没有人想把所有的数据都放到内存中。以块的形式读取字节怎么样?奇怪的是,如果它是一个常规目录,我可以使用管道吗?@psbits:zip格式就是这样工作的。中心目录位于文件的末尾,因此如果不先查找文件的末尾并读取目录,就无法(轻松或正确地)提取文件。goroutine和pipe在这里毫无意义。您仍在同步读取文件,只是无缘无故地添加了另一个副本。@JimB您能解释一下灌浆/管道在这里是如何毫无意义的吗?go例程使管道编写器以块的形式向管道写入,而不会阻止管道读取器从另一端读取。我同意这是一种拷贝,但那不是一次拷贝所有数据吗?也许我可以使用copyN。任何读取/复制都必须分块进行,所以我不确定“一次全部”是什么意思。这里提供的是效率较低的io.Copy
,但根本不需要复制,因为ioutil.ReadAll
无论如何都会将整个文件读取到内存中,所以直接使用它。这很有意义。我试图使用io.Pipe()实现的是将数据块写入管道并从另一端读取,这样我就不必将所有数据一起放入内存。有什么方法可以实现@jimB?管道是不相关的。您可以使用管道将接受io.Reader
的内容同步连接到接受io.Writer
的内容。仅此而已。一次将整个文件读入内存或不读入内存完全取决于您——也就是说,如果您不想全部读取,请不要使用ReadAll
。你在这里似乎有一个XY问题,你需要展示你在努力完成什么,而不是你认为你需要做什么。goroutine和pipe在这里是毫无意义的。您仍在同步读取文件,只是无缘无故地添加了另一个副本。@JimB您能解释一下灌浆/管道在这里是如何毫无意义的吗?go例程使管道编写器以块的形式向管道写入,而不会阻止管道读取器从另一端读取。我同意这是一种拷贝,但那不是一次拷贝所有数据吗?也许我可以使用copyN。任何读取/复制都必须分块进行,所以我不确定“一次全部”是什么意思。这里提供的是效率较低的io.Copy
,但根本不需要复制,因为ioutil.ReadAll
无论如何都会将整个文件读取到内存中,所以直接使用它。这很有意义。我试图使用io.Pipe()实现的是将数据块写入管道并从另一端读取,这样我就不必将所有数据一起放入内存。有什么方法可以实现@jimB?管道是不相关的。您可以使用管道将接受io.Reader
的内容同步连接到接受io.Writer
的内容。仅此而已。一次将整个文件读入内存或不读入内存完全取决于您——也就是说,如果您不想全部读取,请不要使用ReadAll
。你在这里似乎有一个XY问题,你需要展示你正在努力完成什么,而不是你认为你需要做什么。