2017-04-24 105 views
1

我遇到了一些麻烦,想从AWS S3读取GZIP文件。 我只有一个简单的代码,我得到错误panic: runtime error: invalid memory address or nil pointer dereference。但仍然很难找到问题。Golang IO读取文件无效内存地址

错误消息是说这是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

@Flimzy我现在添加了包含注释的完整代码。不,我没有其他任何陈述。我试图在错误检查后添加'defer gzipReader.Close()',但仍然不起作用。 –

+0

@Flimzy我的坏。这是说有问题的一行是'gzip.NewReader(...)'。我试图推迟,但仍然不起作用 –

+0

那么,在你的第一个代码片段结尾处,“// 28行”的含义是什么? – Flimzy

回答

0

问题与defer cancelFn()有关,目前该FUNC没有设置,如果超时是0,这会引发一个空指针的恐慌,所以,你应该将defer移到前面的if语句b因为这是需要使用的唯一一点。 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() 
} 
...