从URL保存图像到文件中。

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

Save an image from url to file

问题

非常新手Go(我正在做的第一个简单项目)。

问题:如何从URL获取图像并将其保存到计算机上?

以下是我目前的代码:

package main

import (
	"fmt"
	"net/http"
	"image"
	"io/ioutil"
)

func main() {
	url := "http://i.imgur.com/m1UIjW1.jpg"
	// 不用担心错误
	response, _ := http.Get(url)

	defer response.Body.Close()
	m, _, err := image.Decode(response.Body)

	err = ioutil.WriteFile("/images/asdf.jpg", m, 0644)
}

然而,当我运行这段代码时,我得到了cannot use m (type image.Image) as type []byte in function argument的错误。

我猜想我需要将image.Image(变量m)转换为未定义数量的字节?这样做是正确的方法吗?

英文:

Very new to Go (first simple project I'm working on).

Question: How do I get an image from URL and then save it to my computer?

Here's what I have so far:

package main

import (
"fmt"
"net/http"
"image"
"io/ioutil"
)

func main() {
        url := "http://i.imgur.com/m1UIjW1.jpg"
        // don't worry about errors
    response, _ := http.Get(url);

    defer response.Body.Close()
    m, _, err := image.Decode(response.Body)

    error := ioutil.WriteFile("/images/asdf.jpg", m, 0644)
}

However, when I run this code, I get cannot use m (type image.Image) as type []byte in function argument

I'm assuming I have to convert image.Image (variable m) into an undefined amount of bytes? Is that the correct way to go about this?

答案1

得分: 49

不需要解码文件。只需将响应主体复制到您打开的文件中。以下是修改后示例中的步骤:

  1. response.Body 是一串数据流,实现了 Reader 接口 - 这意味着您可以按顺序调用 Read 方法,就像它是一个打开的文件一样。
  2. 此处打开的文件实现了 Writer 接口。这是相反的操作 - 它是一个可以调用 Write 方法的流。
  3. io.Copy 将一个读取器和一个写入器“连接”起来,它会消耗读取器流并将其内容写入写入器。

这是 Go 语言中我最喜欢的特性之一 - 隐式接口。您不需要声明您正在实现一个接口,只需要实现它以在某个上下文中使用。这允许混合和匹配不需要了解其交互的其他代码的代码。

package main

import (
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
)

func main() {
	url := "http://i.imgur.com/m1UIjW1.jpg"
	// 不用担心错误
	response, e := http.Get(url)
	if e != nil {
		log.Fatal(e)
	}
	defer response.Body.Close()

	// 打开一个文件进行写入
	file, err := os.Create("/tmp/asdf.jpg")
	if err != nil {
		log.Fatal(err)
	}
	defer file.Close()

	// 使用 io.Copy 将响应主体直接转储到文件中。这支持大文件
	_, err = io.Copy(file, response.Body)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println("Success!")
}

希望对您有所帮助!

英文:

There is no need to decode the file. Simply copy the response body to a file you've opened. Here's the deal in the modified example:

  1. response.Body is a stream of data, and implements the Reader interface - meaning you can sequentially call Read on it, as if it was an open file.
  2. The file I'm opening here implements the Writer interface. This is the opposite - it's a stream you can call Write on.
  3. io.Copy "patches" a reader and a writer, consumes the reader stream and writes its contents to a Writer.

This is one of my favorite things about go - implicit interfaces. You don't have to declare you're implementing an interface, you just have to implement it to be used in some context. This allows mixing and matching of code that doesn't need to know about other code it's interacting with.

package main

import (
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
)

func main() {
	url := "http://i.imgur.com/m1UIjW1.jpg"
	// don't worry about errors
	response, e := http.Get(url)
	if e != nil {
		log.Fatal(e)
	}
	defer response.Body.Close()

	//open a file for writing
	file, err := os.Create("/tmp/asdf.jpg")
	if err != nil {
		log.Fatal(err)
	}
    defer file.Close()

	// Use io.Copy to just dump the response body to the file. This supports huge files
	_, err = io.Copy(file, response.Body)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println("Success!")
}

答案2

得分: 7

以下是代码的中文翻译:

package main

import (
	"io"
	"net/http"
	"os"
	"fmt"
)

func main() {
	img, _ := os.Create("image.jpg")
	defer img.Close()

	resp, _ := http.Get("http://i.imgur.com/Dz2r9lk.jpg")
	defer resp.Body.Close()

	b, _ := io.Copy(img, resp.Body)
	fmt.Println("文件大小:", b)
}

这段代码是一个简单的Go语言程序,它从指定的URL下载一张图片,并将其保存到本地文件中。程序首先创建一个名为image.jpg的文件,然后使用http.Get函数从指定的URL获取图片的内容。接着,使用io.Copy函数将获取到的内容写入到文件中。最后,程序输出文件的大小。

英文:
package main

import (
	"io"
	"net/http"
	"os"
	"fmt"
)

func main() {
	img, _ := os.Create("image.jpg")
	defer img.Close()

	resp, _ := http.Get("http://i.imgur.com/Dz2r9lk.jpg")
	defer resp.Body.Close()

	b, _ := io.Copy(img, resp.Body)
	fmt.Println("File size: ", b)
}

答案3

得分: 2

请尝试以下代码:

package main

import (
	"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()
	// 创建目标文件
	f, e := os.Create(fileName) // "m1UIjW1.jpg";
	if e != nil {
		panic(e)
	}
	defer f.Close()
	// 填充目标文件内容
	n, e := f.ReadFrom(r.Body)
	if e != nil {
		panic(e)
	}
	fmt.Println("文件大小:", n)
}

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)
}

希望对你有帮助!

英文:

Try this:

package main

import (
	"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()
	// Create distination
	f, e := os.Create(fileName) // "m1UIjW1.jpg"
	if e != nil {
		panic(e)
	}
	defer f.Close()
	// Fill distination with content
	n, e := f.ReadFrom(r.Body)
	if e != nil {
		panic(e)
	}
	fmt.Println("File size: ", n)
}

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)
}

答案4

得分: 1

你也可以使用ReadFrom方法:

package main

import (
   "net/http"
   "os"
)

func main() {
   r, e := http.Get("https://i.imgur.com/m1UIjW1.jpg")
   if e != nil {
      panic(e)
   }
   defer r.Body.Close()
   f, e := os.Create("m1UIjW1.jpg")
   if e != nil {
      panic(e)
   }
   defer f.Close()
   f.ReadFrom(r.Body)
}

https://golang.org/pkg/os#File.ReadFrom

英文:

You can also use the ReadFrom method:

package main

import (
   "net/http"
   "os"
)

func main() {
   r, e := http.Get("https://i.imgur.com/m1UIjW1.jpg")
   if e != nil {
      panic(e)
   }
   defer r.Body.Close()
   f, e := os.Create("m1UIjW1.jpg")
   if e != nil {
      panic(e)
   }
   defer f.Close()
   f.ReadFrom(r.Body)
}

https://golang.org/pkg/os#File.ReadFrom

答案5

得分: 0

response.Body的类型是什么?如果它不是[]byte类型,你应该将其转换为[]byte类型,并将其写入磁盘。除非你有某种将数据视为图像的原因,否则没有必要使用image类。只需将数据视为一系列字节,并将其写入磁盘即可。

英文:

What is the type of response.Body? You should just convert that into a []byte if it is not and write that to disk. There is no reason to use the image class unless you have some reason to treat the data as an image. Just treat the data as a series of bytes and write it to the disk.

huangapple
  • 本文由 发表于 2014年3月15日 06:59:21
  • 转载请务必保留本文链接:https://go.coder-hub.com/22417283.html
匿名

发表评论

匿名网友

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

确定