如何从S3读取CSV文件

时间:2018-09-28 03:22:10

标签: csv go amazon-s3 aws-lambda

我有以下代码:

1,hyena
2,lion,https://en.wikipedia.org/wiki/File:Lion_waiting_in_Namibia.jpg
3,zebra

我正在尝试从S3解析CSV文件,对每一行进行一些操作,但是我得到了

package main

import (
    "encoding/csv"
    "fmt"
    "io/ioutil"
    "path"

    "github.com/aws/aws-lambda-go/events"
    "github.com/aws/aws-lambda-go/lambda"
    "github.com/aws/aws-sdk-go/aws"
    "github.com/aws/aws-sdk-go/aws/session"
    "github.com/aws/aws-sdk-go/service/s3"
    "github.com/aws/aws-sdk-go/service/s3/s3iface"
)

var (
    // TOKEN = os.Getenv("TOKEN")
    svc s3iface.S3API
)

func main() {    
    // Panics if there is an error in creating session
    svc = s3iface.S3API(s3.New(session.Must(session.NewSession())))

    lambda.Start(Handler)
}

func Handler(evt events.S3Event) error {

    for _, rec := range evt.Records {

        key := rec.S3.Object.Key

        dir, file := path.Split(key)
        // Download the file from S3
        obj, err := svc.GetObject(&s3.GetObjectInput{
            Bucket: aws.String(rec.S3.Bucket.Name),
            Key:    aws.String(key),
        })
        if err != nil {
            return fmt.Errorf("error in downloading %s from S3: %s\n", key, err)
        }

        body, err := ioutil.ReadAll(obj.Body)
        if err != nil {
            return fmt.Errorf("error in reading file %s: %s\n", key, err)
        }

        reader := csv.NewReader(body)
        record, err := reader.ReadAll()
        if err != nil {
            fmt.Println("Error", err)
        }

        for value := range record { // for i:=0; i<len(record)
            fmt.Println("", record[value])
        }
    }
    return nil
}

任何建议都值得赞赏

1 个答案:

答案 0 :(得分:4)

错误提示:

  

不能在参数io.Reader中使用主体(类型[] byte)   csv.NewReader:     [] byte未实现io.Reader(缺少Read方法)

因为您正在将响应返回的[]byte传递到csv.NewReader

需要通过正文来实现io.Reader,以将其作为参数传递给csv.NewReader。由于它以io.Reader作为参数。尝试将代码更改为:

reader := csv.NewReader(bytes.NewBuffer(body))
record, err := reader.ReadAll()
if err != nil {
    fmt.Println("Error", err)
}

还因为aws.GetObject返回指向GetObjectOutput结构的指针。

func (c *S3) GetObject(input *GetObjectInput) (*GetObjectOutput, error)

本身实现了Reader

type GetObjectOutput struct {
    ....
    // Object data.
    Body io.ReadCloser `type:"blob"`
    ....
}

因此您可以将返回的正文直接传递给csv.NewReader。

另一件事是您可以使用Download Manager

  

s3manager软件包的Downloader提供了同时下载功能   来自S3的对象。下载器将使用以下命令写入S3对象内容   io.WriterAt。创建Downloader实例后,您可以调用   安全地从多个goroutine同时下载。

func (d Downloader) Download(w io.WriterAt, input *s3.GetObjectInput, options ...func(*Downloader)) (n int64, err error)

Download在S3中下载一个对象,并使用并发GET请求将有效负载写入w。

跨goroutine并发调用此方法是安全的。

// The session the S3 Downloader will use
sess := session.Must(session.NewSession())

// Create a downloader with the session and default options
downloader := s3manager.NewDownloader(sess)

// Create a file to write the S3 Object contents to.
f, err := os.Create(filename)
if err != nil {
    return fmt.Errorf("failed to create file %q, %v", filename, err)
}

// Write the contents of S3 Object to the file
n, err := downloader.Download(f, &s3.GetObjectInput{
    Bucket: aws.String(myBucket),
    Key:    aws.String(myString),
})
if err != nil {
    return fmt.Errorf("failed to download file, %v", err)
}