如果我有一些代码,比如下面的示例,从链接中提取图像然后将其保存到磁盘,传递图像数据的最佳方法是什么?
我考虑过使用ioutil.ReadAll(res.Body)
将其转换为[]byte
但是传递它似乎很昂贵,尽管我无法从文档中看出它是否返回切片或数组。我还尝试返回指向res.Body
*io.ReadCloser
类型的指针,但我无法弄清楚如何正确调用指向接口上的.Close()
方法。
我知道将保存代码移动到FetchImage
函数可能是解决此问题的最简单方法,但我希望尽可能将这些部分分开。
type ImageData struct {
Data io.ReadCloser
Name string
}
func FetchImage(url string) (io.ReadCloser, error) {
res, err := http.Get(url)
if err != nil {
return nil, err
}
return res.Body, nil
}
func Save(data *ImageData) error {
defer data.Data.Close()
file, err := os.Create(data.Name)
defer file.Close()
if err != nil {
return err
}
_, err = io.Copy(file, data.Data)
if err != nil {
return err
}
return nil
}
func main() {
body, err := fetcher.FetchImage("https://imgur.com/asdf.jpg")
if err != nil {
panic(err)
}
imageData := ImageData{body, "asdf.jpg"}
saver := Saver{config.BaseDir, 1}
err = saver.Save(&imageData)
if err != nil {
panic(err)
}
}
此外,我是Go的新手,如果此代码中的任何内容看起来很糟糕,请告诉我。
答案 0 :(得分:1)
使用ioutil.ReadAll。该函数返回一个字节片。
切片有效传递。切片是指向后备阵列的指针,长度和容量。
type ImageData struct {
Data []byte
Name string
}
func FetchImage(url string) ([]byte, error) {
res, err := http.Get(url)
if err != nil {
return nil, err
}
defer resp.Body.Close()
if res.StatusCode != 200 {
return nil, fmt.Errorf("%s: %d", url, res.StatusCode)
}
return ioutil.ReadAll(resp.Body)
}
func Save(data *ImageData) error {
file, err := os.Create(data.Name)
if err != nil {
return err
}
defer file.Close()
_, err := file.Write(data.Data)
return err
}
您也可以传递响应正文,但请谨慎使用。必须关闭响应主体才能释放底层连接。问题中的代码确实关闭了响应主体,但是很难看到,因为响应主体在它关闭的函数下传递。
答案 1 :(得分:1)
在Go中,所有数组都有一个大小说明符,看起来像[8]byte
。切片不会有这个,看起来像[]byte
。内部切片只存储指向数据的指针,切片的长度以及切片的容量。这在64位系统上只有24个字节,因此您不必担心传递它。
但是,我建议您从*ImageData
返回FetchImage
,因为它已经包含了像图片名称这样的元数据。
至于为什么你不能指向一个界面,有一个帖子here on SO可以解释原因。
此外,在检查错误之前Save
defer file.Close()
.then(response => {
this.parseJSONContent(response);
})
。你应该交换它,因为如果有错误,文件将是nil,并且可能会发生段错误。