Go语言如何将URL读取的[]byte转换为可写入目标的io.Reader
问题解答
你提供的转换逻辑本身没有语法错误,无法运行的核心原因是http.Response.Body是仅可单次读取的流式对象:如果你的测试代码是在执行完f.ReadFrom(r.Body)之后运行的,此时r.Body的内容已经被全部读取完毕,流指针位于末尾,后续调用buf.ReadFrom(r.Body)只会读取到空内容,自然写入的文件是空的。
如果你需要将同一份图片流写入多个目的地(比如本地文件 + IndexedDB),可以使用两种方案:
方案1:全量读取到内存后复用
先将r.Body的内容一次性全部读取为[]byte,之后需要io.Reader时直接用bytes.NewReader封装即可,示例代码如下:
package main import ( "bytes" "fmt" "net/http" "net/url" "os" "strings" ) var ( fileName string fullUrlFile string ) func main() { fullUrlFile = "https://i.imgur.com/m1UIjW1.jpg" r, e := http.Get(fullUrlFile) if e != nil { panic(e) } defer r.Body.Close() buildFileName() // 第一步:一次性把Body内容全部读到内存中存为[]byte buf := new(bytes.Buffer) _, e = buf.ReadFrom(r.Body) if e != nil { panic(e) } imgBytes := buf.Bytes() // 第二步:封装为io.Reader写入本地文件测试 blobReader := bytes.NewReader(imgBytes) dest, e := os.Create(fileName) if e != nil { panic(e) } defer dest.Close() n2, e := dest.ReadFrom(blobReader) if e != nil { panic(e) } fmt.Printf("写入文件的字节数:%d\n", n2) // 写入IndexedDB时直接传入imgBytes即可 } func buildFileName() { fileUrl, e := url.Parse(fullUrlFile) if e != nil { panic(e) } path := fileUrl.Path segments := strings.Split(path, "/") fileName = segments[len(segments)-1] println(fileName) }
方案2:流式读取无内存缓存(适合大文件)
如果图片体积较大,全量读取到内存会占用过多资源,可以用io.TeeReader实现一次读取同时写入多个目的地,不需要全量缓存:
import "io" // 需要额外导入io包 // 省略其余代码 buf := new(bytes.Buffer) // 构建TeeReader,读取流的同时会把内容写入buf tee := io.TeeReader(r.Body, buf) // 直接写入本地文件 dest, _ := os.Create(fileName) dest.ReadFrom(tee) // 直接从buf拿到所有字节内容 imgBytes := buf.Bytes()
内容的提问来源于stack exchange,提问作者Hasan A Yousef
相关产品推荐
相关产品推荐

