我在尝试从AWS S3读取GZIP文件时遇到了一些麻烦。
我只有一个简单的代码,我收到错误panic: runtime error: invalid memory address or nil pointer dereference
。但它仍然很难找到问题。
错误消息是gzip.NewReader...
。为什么golang
会举报?我怎么能解决它?
goroutine 1 [running]:
github.com/hensg/pushego/aws.GetGZIPProductsDump(0x7ffead44098f, 0xc, 0x7ffead44099f, 0x2f, 0x0, 0xc420190580, 0x0, 0x0)
/home/henrique/go/src/github.com/hensg/pushego/aws/s3.go:47 +0x2e7
main.main()
/home/henrique/go/src/github.com/hensg/pushego/pushego.go:28 +0x249
主要代码(pushego.go)
package main
import (
"bufio"
"flag"
"log"
"os"
"time"
"github.com/hensg/pushego/aws"
)
func init() {
log.SetOutput(os.Stdout)
}
func main() {
log.Println("Starting...")
var bucket, key string
var timeout time.Duration
flag.StringVar(&bucket, "b", "", "Bucket name")
flag.StringVar(&key, "k", "", "Object key name")
flag.DurationVar(&timeout, "d", 0, "Download timeout")
flag.Parse()
gzipReader, err := aws.GetGZIPDump(bucket, key, timeout) // line 28
if err != nil {
log.Fatal("Failed to create GZIP reader")
}
defer gzipReader.Close()
scanner := bufio.NewScanner(gzipReader)
for scanner.Scan() {
log.Printf("Read: %s\n", scanner.Text())
}
log.Printf("Successfully download file from %s/%s\n", bucket, key)
}
Aws代码(aws / s3.go)
package aws
import (
"compress/gzip"
"context"
"log"
"time"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/aws/request"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/s3"
)
func GetGZIPProductsDump(bucket, key string, timeout time.Duration) (*gzip.Reader, error) {
sess := session.Must(session.NewSession())
svc := s3.New(sess)
// Create a context with a timeout that will abort the download if it takes
// more than the passed in timeout.
ctx := context.Background()
var cancelFn func()
if timeout > 0 {
ctx, cancelFn = context.WithTimeout(ctx, timeout)
}
// Ensure the context is canceled to prevent leaking.
// See context package for more information, https://golang.org/pkg/context/
defer cancelFn()
// Uploads the object to S3. The Context will interrupt the request if the
// timeout expires.
resp, err := svc.GetObjectWithContext(ctx, &s3.GetObjectInput{
Bucket: aws.String(bucket),
Key: aws.String(key),
})
if err != nil {
if aerr, ok := err.(awserr.Error); ok && aerr.Code() == request.CanceledErrorCode {
// If the SDK can determine the request or retry delay was canceled
// by a context the CanceledErrorCode error code will be returned.
log.Fatal("Download canceled due to timeout, %v\n", err)
} else {
log.Fatal("Failed to download object, %v\n", err)
}
}
return gzip.NewReader(resp.Body) // line 47
}
答案 0 :(得分:0)
问题与defer cancelFn()
有关,目前如果超时为0则未设置func,这会引发带有空指针的恐慌,因此,您应该移动defer
内部的之前的if语句,因为它是唯一需要使用的时间点。 aws/s3.go
的代码必须如下所示。
...
// Create a context with a timeout that will abort the download if it takes
// more than the passed in timeout.
ctx := context.Background()
var cancelFn func()
if timeout > 0 {
ctx, cancelFn = context.WithTimeout(ctx, timeout)
// Ensure the context is canceled to prevent leaking.
// See context package for more information, https://golang.org/pkg/context/
defer cancelFn()
}
...