使用Golang将文件上传到S3的方法是使用`os.Open`函数。

huangapple go评论92阅读模式
英文:

Golang file upload to s3 using OS Open

问题

我正在尝试使用Golang和Amazon S3 API将图像上传到我的S3账户。如果我硬编码直接路径,例如:

file, err := os.Open("/Users/JohnSmith/Documents/pictures/cars.jpg")
defer file.Close()
if err != nil {
    fmt.Printf("打开文件时出错:%s", err)
}

如果我像上面那样硬编码文件路径,那么图片将被上传到我的S3账户。然而,这种方法并不好,因为我显然不能为每个要上传的图片硬编码直接路径。我的问题是,如何在不硬编码路径的情况下上传图片。这将是一个用户上传图片的API的一部分,所以我显然不能有一个硬编码的路径。这是我的代码,首先是HTML部分:

<form method="post" enctype="multipart/form-data" action="profile_image">
    <h2>图片上传</h2>
    <p><input type="file" name="file" id="file"/> </p>
    <p> <input type="submit" value="上传图片"></p>

</form>

然后是我的HTTP Post函数方法:

func UploadProfile(w http.ResponseWriter, r *http.Request) {

    r.ParseForm()
    var resultt string
    resultt = "Hi"

    sess, _ := session.NewSession(&aws.Config{
        Region:      aws.String("us-west-2"),
        Credentials: credentials.NewStaticCredentials(aws_access_key_id,aws_secret_access_key, ""),

    })
    svc := s3.New(sess)

    file, err := os.Open("Users/JohnSmith/Documents/pictures/cars.jpg")
    defer file.Close()
    if err != nil {
        fmt.Printf("打开文件时出错:%s", err)
    }

    fileInfo, _ := file.Stat()
    size := fileInfo.Size()
    buffer := make([]byte, size) // read file content to buffer

    file.Read(buffer)
    fileBytes := bytes.NewReader(buffer)
    fileType := http.DetectContentType(buffer)
    path := file.Name()
    params := &s3.PutObjectInput{
        Bucket: aws.String("my-bucket"),
        Key: aws.String(path),
        Body: fileBytes,
        ContentLength: aws.Int64(size),
        ContentType: aws.String(fileType),
    }
    resp, err := svc.PutObject(params)
    if err != nil {
        fmt.Printf("响应错误:%s", err)
    }
    fmt.Printf("响应:%s", awsutil.StringValue(resp))

}

以上是我的完整代码,然而,当我尝试这样做时:

file, err := os.Open("file")
defer file.Close()
if err != nil {
    fmt.Printf("打开文件时出错:%s", err)
}

我得到以下错误:

http: panic serving [::1]:55454: runtime error: invalid memory address or nil pointer dereference
goroutine 7 [running]:
err opening file: open file: no such file or directorynet/http.(*conn).serve.func1(0xc420076e80)

我不能使用绝对路径*(filepath.Abs())*,因为一些文件将位于GoPath之外,并且正如前面所述,其他用户将上传文件。有没有办法获取相对路径..

英文:

I am trying to upload an Image to my s3 account using Golang and the amazon s3 api . I can get the imagine uploaded if I hard code the direct path such as

file, err :=  os.Open(&quot;/Users/JohnSmith/Documents/pictures/cars.jpg&quot;)
	defer file.Close()
	if err != nil {
		fmt.Printf(&quot;err opening file: %s&quot;, err)
	}

if I hard code the file path like that then the picture will be uploaded to my s3 account . However that approach is not good as I can't obviously hard code the direct image path to every image that I want to upload . My question is how can I upload images without having to Hardcode the path . This will be apart of an API where users will upload images so I clearly can not have a hard coded path . This is my code first the HTML

&lt;form method=&quot;post&quot; enctype=&quot;multipart/form-data&quot;  action=&quot;profile_image&quot;&gt;
    &lt;h2&gt;Image Upload&lt;/h2&gt;
    &lt;p&gt;&lt;input type=&quot;file&quot; name=&quot;file&quot; id=&quot;file&quot;/&gt; &lt;/p&gt;
       &lt;p&gt; &lt;input type=&quot;submit&quot; value=&quot;Upload Image&quot;&gt;&lt;/p&gt;

&lt;/form&gt;

then this is my HTTP Post function method

func UploadProfile(w http.ResponseWriter, r *http.Request) {

	r.ParseForm()
      var resultt string
	resultt = &quot;Hi&quot;

	sess, _ := session.NewSession(&amp;aws.Config{
		Region:      aws.String(&quot;us-west-2&quot;),
		Credentials: credentials.NewStaticCredentials(aws_access_key_id,aws_secret_access_key, &quot;&quot;),


	})
	svc := s3.New(sess)

file, err :=  os.Open(&quot;Users/JohnSmith/Documents/pictures/cars.jpg&quot;)
defer file.Close()
if err != nil {
	fmt.Printf(&quot;err opening file: %s&quot;, err)
}



fileInfo, _ := file.Stat()
size := fileInfo.Size()
buffer := make([]byte, size) // read file content to buffer

file.Read(buffer)
fileBytes := bytes.NewReader(buffer)
fileType := http.DetectContentType(buffer)
path := file.Name()
params := &amp;s3.PutObjectInput{
	Bucket: aws.String(&quot;my-bucket&quot;),
	Key: aws.String(path),
	Body: fileBytes,
	ContentLength: aws.Int64(size),
	ContentType: aws.String(fileType),
}
resp, err := svc.PutObject(params)
if err != nil {
	fmt.Printf(&quot;bad response: %s&quot;, err)
}
fmt.Printf(&quot;response %s&quot;, awsutil.StringValue(resp))

}

That is my full code above however when I try to do something such as

file, err :=  os.Open(&quot;file&quot;)
	defer file.Close()
	if err != nil {
		fmt.Printf(&quot;err opening file: %s&quot;, err)
	}

I get the following error

http: panic serving [::1]:55454: runtime error: invalid memory address or nil pointer dereference
goroutine 7 [running]:
err opening file: open file: no such file or directorynet/http.(*conn).serve.func1(0xc420076e80)

I can't use absolute path (filepath.Abs()) because some of the files will be outside of the GoPath and as stated other users will be uploading. Is there anyway that I can get a relative path ..

答案1

得分: 2

在向您的API发送POST请求后,默认情况下,图像会被临时保存在操作系统的临时目录中(不同的操作系统有不同的目录)。要获取此目录,您可以使用以下代码:

func GetTempLoc(filename string) string {
    return strings.TrimRight(os.TempDir(), "/") + "/" + filename
}

其中:

  • filename 是 header.Filename,即您在POST请求中接收到的文件名。在 Gin-Gonic 框架中,您可以在请求处理程序中获取它:
file, header, err := c.Request.FormFile("file")
if err != nil {
    return out, err
}
defer file.Close()

示例:https://github.com/gin-gonic/gin#another-example-upload-file。

我相信在您的框架中会有类似的功能。

  • os.TempDir() 是一个函数,用于获取临时文件夹(详细信息:https://golang.org/pkg/os/#TempDir)。
  • TrimRight 用于确保 os.TempDir 的结果在不同的操作系统上保持一致。

然后,您可以使用以下代码来使用它:

file, err := os.Open(GetTempLoc(fileName))
...
英文:

After POST to your API, images are temporarily saved in a OS's temp directory (different for different OS's) by default. To get this directory you can use, for example:

func GetTempLoc(filename string) string {
    return strings.TrimRight(os.TempDir(), &quot;/&quot;) + &quot;/&quot; + filename
}

Where:

  • filename is a header.Filename, i.e. file name received in your POST request. In Gin-Gonic framework you get it in your request handler as:

<!-- language: go -->

file, header, err := c.Request.FormFile(&quot;file&quot;)
if err != nil {
	return out, err
}
defer file.Close()

Example: https://github.com/gin-gonic/gin#another-example-upload-file.

I'm sure in your framework there will be an analogue.

  • os.TempDir() is a function go give you a temp folder (details: https://golang.org/pkg/os/#TempDir).
  • TrimRight is used to ensure result of os.TempDir is consistent on different OSs

And then you use it as

file, err := os.Open(GetTempLoc(fileName))
...

huangapple
  • 本文由 发表于 2016年12月17日 11:53:30
  • 转载请务必保留本文链接:https://go.coder-hub.com/41195209.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定