为了账号安全,请及时绑定邮箱和手机立即绑定

如何将 io.Reader 实例传递给 Golang 中的函数?

如何将 io.Reader 实例传递给 Golang 中的函数?

Go
Helenr 2022-10-17 16:03:52
我一直在处理一个问题,我必须将一个io.Reader实例作为参数放入由 api 作为端点提供的函数中。我需要做的任务是将本地文件夹上传到公司的云存储。func (s *server) uploadFileToPutIo(w http.ResponseWriter, r *http.Request) {    tokenSource := oauth2.StaticTokenSource(&oauth2.Token{AccessToken: token})    oauthClient := oauth2.NewClient(context.TODO(), tokenSource)    client := putio.NewClient(oauthClient)    var testIO io.Reader // ?     upload, err := client.Files.Upload(context.TODO(), testIO, "test", 0)    if err != nil {        log.Fatal(err)    }    fmt.Println(upload.File)    sendResponse(w, []byte("successful"), http.StatusOK)}/upload当我在 POST 方法下向这个端点发出请求时。我收到以下错误。2021/12/01 18:28:47 http: panic serving 127.0.0.1:61057: runtime error: invalid memory address or nil pointer dereferencegoroutine 8 [running]:net/http.(*conn).serve.func1(0xc000108d20)        /usr/local/Cellar/go/1.16.6/libexec/src/net/http/server.go:1804 +0x153panic(0x1390ae0, 0x164fdd0)        /usr/local/Cellar/go/1.16.6/libexec/src/runtime/panic.go:971 +0x499io.copyBuffer(0x1462700, 0xc000026360, 0x0, 0x0, 0xc000170000, 0x8000, 0x8000, 0x0, 0x0, 0x13d5e01)        /usr/local/Cellar/go/1.16.6/libexec/src/io/io.go:423 +0x10bio.Copy(...)        /usr/local/Cellar/go/1.16.6/libexec/src/io/io.go:382github.com/putdotio/go-putio/putio.(*FilesService).Upload(0xc000010088, 0x1468390, 0xc00001c088, 0x0, 0x0, 0x13ef46f, 0x6, 0x0, 0x170d108, 0x90, ...)        /Users/barisertas/go/pkg/mod/github.com/putdotio/go-putio/putio@v0.0.0-20200123120452-16d982cac2b8/files.go:235 +0x187main.(*server).uploadFileToPutIo(0xc000010028, 0x1467d60, 0xc00014a2a0, 0xc000154500)        /Users/barisertas/workspace/mini-project/api/handler.go:79 +0xe5net/http.HandlerFunc.ServeHTTP(0xc000012db0, 0x1467d60, 0xc00014a2a0, 0xc000154500)        /usr/local/Cellar/go/1.16.6/libexec/src/net/http/server.go:2049 +0x44github.com/gorilla/mux.(*Router).ServeHTTP(0xc000144000, 0x1467d60, 0xc00014a2a0, 0xc000154300)        /Users/barisertas/go/pkg/mod/github.com/gorilla/mux@v1.8.0/mux.go:210 +0xd3
查看完整描述

3 回答

?
皈依舞

TA贡献1851条经验 获得超3个赞

runtime error: invalid memory address or nil pointer dereference

你肯定知道,这是因为你声明了 anio.Reader但你没有设置它的值,所以它仍然等于接口的默认值,即nil.

    var testIO io.Reader // ?

传递io.Readerto的Upload目的是提供要上传的数据。通过传递io.Reader,任意数据源可以提供任意数量的字节,不受内存可用性的限制(与 不同[]byte,它需要在上传 之前将所有数据保存在内存中)。io.Reader通常用于为这种“流式传输”操作提供数据。

Upload reads from given io.Reader and uploads the file contents

io.Reader应该是要上传的数据的来源。

io.Reader可能是来自os.Open().

但它可以是任何满足的东西io.Reader——例如,它也可以是bytes.Buffer.

它甚至可能是更深奥的东西,比如对GetObject来自 AWS 的流行 S3 服务的 API 调用的结果,它也返回一个io.ReadCloserwhich satisfies io.Reader

io.Reader是 Go 接口如何允许独立库相互连接的一个很好的例子。您使用的 SDK 并不关心io.Reader它传递了什么;值满足就足够了,这是io.Reader在编译时强制执行的要求。您可以将任何满足io.Reader的东西传递给它,并且接口类型保证Upload()能够正确处理它。

Upload需要一个io.Reader. 如果你想传递类似*os.Filefromos.Openio.ReadCloserfrom 之类的东西,比如 S3 GetObject,那会起作用,因为*os.Fileio.ReadCloser满足 io.Reader。但是由于Upload需要io.Reader,您可以确信它只会调用io.Reader. 这意味着你必须在Upload被调用后自己关闭。

确保花时间了解如何io.Reader让这个函数的输入保持开放式,同时还要具体说明它所期望的接口。这是 Go 中最重要的概念之一。


查看完整回答
反对 回复 2022-10-17
?
慕姐8265434

TA贡献1813条经验 获得超2个赞

这个:


var testIO io.Reader

相当于:


testIO := io.Reader(nil)

所以这就是为什么你对零指针引用感到恐慌的原因:


2021/12/01 18:28:47 http: panic serving 127.0.0.1:61059: runtime error: invalid memory address or nil pointer dereference

goroutine 11 [running]:

io.Reader是一个允许传递通用值的接口,前提是它们实现了接口(即实现方法Read)。


由于您正在上传文件,因此您的字节流应该来自操作系统文件。os.File实现了正确的Read方法 - 所以是兼容的io.Reader。


所以试试:


f, err := os.Open(uploadFilePath)

if err != nil { /* ... */ }


upload, err := client.Files.Upload(context.TODO(), f, "test", 0)


查看完整回答
反对 回复 2022-10-17
?
阿晨1998

TA贡献2037条经验 获得超6个赞

当你定义一个变量时,它的初始值就是zero value那个类型的。io.Reader是一个接口,它的零值是nil。因此 nil pointer dereference error. io.Reader只需在将其传递给 Upload 之前对其进行初始化:


file, err := os.Open("path/to/file")

// if err != nil { ... }


upload, err := client.Files.Upload(context.TODO(), file, "test", 0)


查看完整回答
反对 回复 2022-10-17
  • 3 回答
  • 0 关注
  • 139 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信