Golang通过多部分处理图像并流式传输到Azure
在学习golang的过程中,我正在尝试编写一个具有多种图像上传功能的web应用程序 我正在使用Azure Blob存储来存储图像,但无法将图像从多部分请求流式传输到Blob存储 以下是我迄今为止编写的处理程序:Golang通过多部分处理图像并流式传输到Azure,azure,go,image-uploading,azure-storage-blobs,Azure,Go,Image Uploading,Azure Storage Blobs,在学习golang的过程中,我正在尝试编写一个具有多种图像上传功能的web应用程序 我正在使用Azure Blob存储来存储图像,但无法将图像从多部分请求流式传输到Blob存储 以下是我迄今为止编写的处理程序: func (imgc *ImageController) UploadInstanceImageHandler(w http.ResponseWriter, r *http.Request, p httprouter.Params) { reader, err := r.Multipar
func (imgc *ImageController) UploadInstanceImageHandler(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
reader, err := r.MultipartReader()
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
for {
part, partErr := reader.NextPart()
// No more parts to process
if partErr == io.EOF {
break
}
// if part.FileName() is empty, skip this iteration.
if part.FileName() == "" {
continue
}
// Check file type
if part.Header["Content-Type"][0] != "image/jpeg" {
fmt.Printf("\nNot image/jpeg!")
break
}
var read uint64
fileName := uuid.NewV4().String() + ".jpg"
buffer := make([]byte, 100000000)
// Get Size
for {
cBytes, err := part.Read(buffer)
if err == io.EOF {
fmt.Printf("\nLast buffer read!")
break
}
read = read + uint64(cBytes)
}
stream := bytes.NewReader(buffer[0:read])
err = imgc.blobClient.CreateBlockBlobFromReader(imgc.imageContainer, fileName, read, stream, nil)
if err != nil {
fmt.Println(err)
break
}
}
w.WriteHeader(http.StatusOK)
}
在我的研究过程中,我通读了使用r.FormFile、ParseMultipartForm,但决定尝试学习如何使用MultiPartReader
我能够上传一个图像到golang后端,并使用MultiPartReader将文件保存到我的机器上
目前,我可以将文件上传到Azure,但最终它们被破坏了。文件大小似乎很合适,但显然有些东西不起作用
我是否误解了如何为CreateBlockBlobFromReader创建io.Reader
非常感谢您的帮助 A可以返回io.EOF和有效的最终读取字节,看起来最终字节(cBytes)没有添加到read
总字节中。另外,要小心:如果由io.EOF以外的part.Read(buffer)
返回错误,则读取循环可能不会退出。考虑一下。
CreateBlockBlobFromReader接受一个读卡器,而part是一个读卡器,因此您可以直接传递part
你可能还想考虑到Azure块大小的限制可能比图像小,参见
< P> AS @马克说,你可以使用内容读取到一个字节数组中,下面的代码如下。import (
"bytes"
"io/ioutil"
)
partBytes, _ := ioutil.ReadAll(part)
size := uint64(len(partBytes))
blob := bytes.NewReader(partBytes)
err := blobClient.CreateBlockBlobFromReader(container, fileName, size, blob, nil)
import "encoding/base64"
const BLOB_LENGTH_LIMITS uint64 = 64 * 1024 * 1024
partBytes, _ := ioutil.ReadAll(part)
size := uint64(len(partBytes))
if size <= BLOB_LENGTH_LIMITS {
blob := bytes.NewReader(partBytes)
err := blobClient.CreateBlockBlobFromReader(container, fileName, size, blob, nil)
} else {
// Create an empty blob
blobClient.CreateBlockBlob(container, fileName)
// Create a block list, and upload each block
length := size / BLOB_LENGTH_LIMITS
if length%limits != 0 {
length = length + 1
}
blocks := make([]Block, length)
for i := uint64(0); i < length; i++ {
start := i * BLOB_LENGTH_LIMITS
end := (i+1) * BLOB_LENGTH_LIMITS
if end > size {
end = size
}
chunk := partBytes[start: end]
blockId := base64.StdEncoding.EncodeToString(chunk)
block := Block{blockId, storage.BlockStatusCommitted}
blocks[i] = block
err = blobClient.PutBlock(container, fileName, blockID, chunk)
if err != nil {
.......
}
}
err = blobClient.PutBlockList(container, fileName, blocks)
if err != nil {
.......
}
}
根据godoc,如下所示
API拒绝大小>64 MiB的请求(但SDK不检查此限制)。要编写更大的blob,请使用、PutBlock和PutBlockList
因此,如果大小大于64MB,代码应该如下所示
import (
"bytes"
"io/ioutil"
)
partBytes, _ := ioutil.ReadAll(part)
size := uint64(len(partBytes))
blob := bytes.NewReader(partBytes)
err := blobClient.CreateBlockBlobFromReader(container, fileName, size, blob, nil)
import "encoding/base64"
const BLOB_LENGTH_LIMITS uint64 = 64 * 1024 * 1024
partBytes, _ := ioutil.ReadAll(part)
size := uint64(len(partBytes))
if size <= BLOB_LENGTH_LIMITS {
blob := bytes.NewReader(partBytes)
err := blobClient.CreateBlockBlobFromReader(container, fileName, size, blob, nil)
} else {
// Create an empty blob
blobClient.CreateBlockBlob(container, fileName)
// Create a block list, and upload each block
length := size / BLOB_LENGTH_LIMITS
if length%limits != 0 {
length = length + 1
}
blocks := make([]Block, length)
for i := uint64(0); i < length; i++ {
start := i * BLOB_LENGTH_LIMITS
end := (i+1) * BLOB_LENGTH_LIMITS
if end > size {
end = size
}
chunk := partBytes[start: end]
blockId := base64.StdEncoding.EncodeToString(chunk)
block := Block{blockId, storage.BlockStatusCommitted}
blocks[i] = block
err = blobClient.PutBlock(container, fileName, blockID, chunk)
if err != nil {
.......
}
}
err = blobClient.PutBlockList(container, fileName, blocks)
if err != nil {
.......
}
}
导入“编码/base64”
常量块长度限制uint64=64*1024*1024
partBytes,Util:=ioutil.ReadAll(部分)
大小:=uint64(len(partBytes))
如果大小{
结束=大小
}
chunk:=partBytes[开始:结束]
blockId:=base64.StdEncoding.EncodeToString(块)
块:=块{blockId,storage.BlockStatusCommitted}
块[i]=块
err=blobClient.PutBlock(容器、文件名、块ID、块)
如果出错!=零{
.......
}
}
err=blobClient.PutBlockList(容器、文件名、块)
如果出错!=零{
.......
}
}
希望有帮助。你好,马克,谢谢你的回答。我试图看看是否可以将部分内容直接传递给CreateBlockBlobFromReader,但我从Azure得到一个错误,说正文长度为0,因此与内容长度不匹配(我作为“读取”传递)。你知道为什么吗?我将再次尝试直接传递部分内容。Andrew看到了上面Peter的有用答案。感谢您回答@Peter,您知道为什么CreateBlockBlobFromReader与reader一起需要前面的大小吗?@Mark Azure Storage SDK for Golang或其他语言是包装存储REST API。rest请求中的/require
Content-Length
头。