【问题标题】:Golang processing images via multipart and streaming to AzureGolang 通过多部分处理图像并流式传输到 Azure
【发布时间】:2017-08-28 11:32:34
【问题描述】:

在学习golang的过程中,我正在尝试编写一个具有多个图片上传功能的网络应用程序。

我正在使用 Azure Blob 存储来存储图像,但我无法将图像从多部分请求流式传输到 Blob 存储。

这是我目前编写的处理程序:

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?

非常感谢任何帮助!

【问题讨论】:

    标签: azure go image-uploading azure-blob-storage


    【解决方案1】:

    正如@Mark 所说,您可以使用ioutil.ReadAll 将内容读入字节数组,代码如下。

    import (
       "bytes"
       "io/ioutil"
    )
    
    partBytes, _ := ioutil.ReadAll(part)
    size := uint64(len(partBytes))
    blob := bytes.NewReader(partBytes)
    err := blobClient.CreateBlockBlobFromReader(container, fileName, size, blob, nil)
    

    根据CreateBlockBlobFromReader的godoc,如下。

    API 拒绝 大小 > 64 MiB 的请求(但 SDK 不检查此限制)。要编写更大的 blob,请使用 CreateBlockBlob、PutBlock 和 PutBlockList。

    所以如果大小大于 64MB,代码应该如下所示。

    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 {
          .......
       }
    }
    

    希望对你有帮助。

    【讨论】:

    • 感谢@Peter 的回答,您知道为什么 CreateBlockBlobFromReader 需要在阅读器旁边预先设置大小吗?
    • @Mark Azure Storage SDK for Golang 或其他语言是封装的存储 REST API。 Put Blob/Put Block 在 rest 请求中需要 Content-Length 标头。
    【解决方案2】:

    Reader 可以返回 io.EOF 和读取的有效最终字节,看起来最终字节 (cBytes) 未添加到 read 总字节中。另外,请注意:如果part.Read(buffer) 返回的错误不是 io.EOF,则读取循环可能不会退出。请考虑使用ioutil.ReadAll。

    CreateBlockBlobFromReader 带一个Reader,part 是Reader,所以可以直接传入part。

    您可能还需要考虑 Azure 块大小限制可能小于图像,请参阅 Asure blobs。

    【讨论】:

    • 嗨,马克,感谢您的回答。我试图查看是否可以部分直接传递给 CreateBlockBlobFromReader,但我从 Azure 收到一个错误,说正文长度为 0,因此与 Content-Length 不匹配(我作为“读取”传入) .你知道这是为什么吗?我会尝试再次直接部分传递。
    • 安德鲁看到上面彼得的有用答案。
    猜你喜欢
    • 2016-04-27
    • 1970-01-01
    • 2019-03-05
    • 2013-09-13
    • 1970-01-01
    • 1970-01-01
    • 2011-02-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多