来自 inputStream 的内容的 HTTP PUT 请求,大小未知,无法在 HttpUrlConnection 中设置 ChunkedStreamingMode

Posted

技术标签:

【中文标题】来自 inputStream 的内容的 HTTP PUT 请求,大小未知,无法在 HttpUrlConnection 中设置 ChunkedStreamingMode【英文标题】:HTTP PUT request by content from inputStream with unknown size and can not set ChunkedStreamingMode in HttpUrlConnection 【发布时间】:2021-07-04 10:21:55 【问题描述】:

我正在尝试向 Azure Blob 存储发送 HTTP PUT 请求,但不允许使用 ChunkedStreamingMode。我正在从大小未知的 InputStream 中读取数据。我可以将 PUT Blob 请求分成多个 PUT Block 请求(Azure Blob Storage 提供了一个 PUT BLOCK 操作来存储单个块,最后,我可以将所有块构建到一个 Blob)。在内存中缓冲 1 MiB 并像块一样发送它是一个好的解决方案吗?还是从输入流中读取并保存到本地文件系统中的临时文件中,然后读取文件并将其作为 Block 发送是更好的解决方案?

【问题讨论】:

您可以发布您尝试使用的代码吗?看起来 C# 的 Azure SDK 支持块:***.com/questions/61481720/… 所以在 Java 中也应该可以。 我没有使用 Azure SDK。 我认为 Azure SDK 使用的是 REST API(虽然我并不真正知道它是如何工作的),所以通过查看 Azure SDK 的源代码,您应该能够弄清楚它们的作用。 怎么样?你的问题得到解决了吗?如果您还有其他问题,请告诉我 我已经通过将 InputStream 存储在一个临时文件中来实现它。我没有使用 Azure SDK,所以我自己通过 REST API 实现了它。 【参考方案1】:

根据我的理解,您想逐块上传一个大文件。我认为您的两个解决方案都可以工作,我将为您的第二个解决方案提供一些示例代码:将输入流保存为临时文件并逐块上传,只需通过 Azure Blob SDK 尝试以下代码:

import java.time.Duration;

import com.azure.storage.blob.BlobClient;
import com.azure.storage.blob.BlobServiceClientBuilder;
import com.azure.storage.blob.ProgressReceiver;
import com.azure.storage.blob.models.AccessTier;
import com.azure.storage.blob.models.BlobHttpHeaders;
import com.azure.storage.blob.models.BlobRequestConditions;
import com.azure.storage.blob.models.ParallelTransferOptions;

public class StorageTest 

    public static void main(String[] args) 
        //skip the process about saving a temp file, just leaving its path 
        String tempFilePath = "";

        String connString = "<azure storage connection string>";
        String containerName = "<container name>";
        String destBlobName = "<blob name with path>";

        BlobClient blobClient = new BlobServiceClientBuilder().connectionString(connString).buildClient()
                .getBlobContainerClient(containerName).getBlobClient(destBlobName);
        // 1MB per request in case of consuming too much jvm memory while uploading
        long blockSize = 1024 * 1024;
        ParallelTransferOptions parallelTransferOptions = new ParallelTransferOptions().setBlockSizeLong(blockSize)
                // 2 Concurrency requests as max,you can set more than it to accelerate uploading
                .setMaxConcurrency(2)
                .setProgressReceiver(new ProgressReceiver() 
                    @Override
                    public void reportProgress(long bytesTransferred) 
                        System.out.println("uploaded:" + bytesTransferred);
                    
                );

        BlobHttpHeaders headers = new BlobHttpHeaders().setContentLanguage("en-US").setContentType("binary");

        blobClient.uploadFromFile(tempFilePath, parallelTransferOptions, headers, null, AccessTier.HOT,
                new BlobRequestConditions(), Duration.ofMinutes(30));

    


我已经测试过,我可以上传一个 5GB 的文件。 如果您还有其他问题,请告诉我。

【讨论】:

以上是关于来自 inputStream 的内容的 HTTP PUT 请求,大小未知,无法在 HttpUrlConnection 中设置 ChunkedStreamingMode的主要内容,如果未能解决你的问题,请参考以下文章

来自相对路径的 InputStream

来自 InputStream 的文件路径/名称

以 InputStream 格式将文本文件从 .Net http 客户端上传到 Java REST API

从来自 java 中 InputStream 的字符串创建 Spark RDD 或数据帧

来自 jar-File 的 InputStream 始终返回 null

如何通过表单上传文件并让 Java 将其作为 InputStream 处理? [复制]