2017-04-24 102 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() 
} 
...