2017-04-24 19 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

最初のコードスニペットの最後にある '// line 28'の意味は何ですか? – Flimzy

答えて

0

問題は、defer cancelFn()と関連している現在そのFUNCタイムアウトが0の場合に設定されていない場合、これはヌルポインタを持つパニックを引き起こすので、前のifステートメントの中にdeferを移動する必要があります。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() 
} 
... 
関連する問題