当前位置: 首页 > 知识库问答 >
问题:

使用有限堆的azure-sdk-for-java上传大文件

季炯
2023-03-14

我们正在开发需要使用Azure作为文件内容存储的文档微服务。Azure Block Blob似乎是一个合理的选择。文档服务的堆限制为512MB(-Xmx512m)。

我没有成功地让流文件上传与有限的堆使用azure-store age-blob: 12.10.0-beta.1(也在12.9.0上测试)。

尝试了以下方法:

  1. 使用BlockBlobClient
BlockBlobClient blockBlobClient = blobContainerClient.getBlobClient("file").getBlockBlobClient();

File file = new File("file");

try (InputStream dataStream = new FileInputStream(file)) {
  blockBlobClient.upload(dataStream, file.length(), true /* overwrite file */);
}

结果:java.io.IOExctive:不支持标记/重置-SDK尝试使用标记/重置,即使文件输入流报告不支持此功能。

BlockBlobClient blockBlobClient = blobContainerClient.getBlobClient("file").getBlockBlobClient();

File file = new File("file");

try (InputStream dataStream = new BufferedInputStream(new FileInputStream(file))) {
  blockBlobClient.upload(dataStream, file.length(), true /* overwrite file */);
}

结果:java。lang.OutOfMemoryError:Java堆空间。我假设SDK试图将所有1.17GB的文件内容加载到内存中。

BlobClient blobClient = blobContainerClient.getBlobClient("file");

File file = new File("file");

try (InputStream dataStream = new FileInputStream(file)) {
  blobClient.upload(dataStream, file.length(), true /* overwrite file */);
}

结果:使用了1.5GB堆内存,所有文件内容都加载到内存中,并在Reactor一侧进行了一些缓冲

从VisualVM堆使用

long blockSize = DataSize.ofMegabytes(4L).toBytes();

BlockBlobClient blockBlobClient = blobContainerClient.getBlobClient("file").getBlockBlobClient();

// create / erase blob
blockBlobClient.commitBlockList(List.of(), true);

BlockBlobOutputStreamOptions options = (new BlockBlobOutputStreamOptions()).setParallelTransferOptions(
  (new ParallelTransferOptions()).setBlockSizeLong(blockSize).setMaxConcurrency(1).setMaxSingleUploadSizeLong(blockSize));

try (InputStream is = new FileInputStream("file")) {
  try (OutputStream os = blockBlobClient.getBlobOutputStream(options)) {
    IOUtils.copy(is, os); // uses 8KB buffer
  }
}

结果:文件在上载过程中损坏。Azure web portal显示的是1.09GB,而不是预期的1.17GB。从Azure web portal手动下载文件确认文件内容在上载过程中已损坏。内存占用显著减少,但文件损坏是一个阻碍因素。

问题:无法提供内存占用小的工作上载/下载解决方案

任何帮助都将不胜感激!

共有1个答案

燕翔飞
2023-03-14

请尝试下面的代码来上传/下载大文件,我已经用一个。大小约为1.1 GB的zip文件

上传文件:

public static void uploadFilesByChunk() {
                String connString = "<conn str>";
                String containerName = "<container name>";
                String blobName = "UploadOne.zip";
                String filePath = "D:/temp/" + blobName;

                BlobServiceClient client = new BlobServiceClientBuilder().connectionString(connString).buildClient();
                BlobClient blobClient = client.getBlobContainerClient(containerName).getBlobClient(blobName);
                long blockSize = 2 * 1024 * 1024; //2MB
                ParallelTransferOptions parallelTransferOptions = new ParallelTransferOptions()
                                .setBlockSizeLong(blockSize).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(filePath, parallelTransferOptions, headers, null, AccessTier.HOT,
                                new BlobRequestConditions(), Duration.ofMinutes(30));
        }

下载文件:

public static void downLoadFilesByChunk() {
                String connString = "<conn str>";
                String containerName = "<container name>";
                String blobName = "UploadOne.zip";

                String filePath = "D:/temp/" + "DownloadOne.zip";

                BlobServiceClient client = new BlobServiceClientBuilder().connectionString(connString).buildClient();
                BlobClient blobClient = client.getBlobContainerClient(containerName).getBlobClient(blobName);
                long blockSize = 2 * 1024 * 1024;
                com.azure.storage.common.ParallelTransferOptions parallelTransferOptions = new com.azure.storage.common.ParallelTransferOptions()
                                .setBlockSizeLong(blockSize).setMaxConcurrency(2)
                                .setProgressReceiver(new com.azure.storage.common.ProgressReceiver() {
                                        @Override
                                        public void reportProgress(long bytesTransferred) {
                                                System.out.println("dowloaded:" + bytesTransferred);
                                        }
                                });

                BlobDownloadToFileOptions options = new BlobDownloadToFileOptions(filePath)
                                .setParallelTransferOptions(parallelTransferOptions);
                blobClient.downloadToFileWithResponse(options, Duration.ofMinutes(30), null);
        }
 类似资料:
  • 我使用AWS文档中的以下代码: http://docs.aws.amazon.com/amazons3/latest/dev/uploadobjsingleopjava.html 我得到以下错误:

  • 可能没有多少开发人员像我一样面临这个问题<但是我想分享我已经解决了将近一个月的解决方案 我使用Kubernetes和docker compose,此Webflux服务(容器)设置了内存限制1g

  • 我正在尝试使用AWS SDK 2.0将文件上传到AWS S3存储桶Java,但我在尝试这样做时收到错误。 我不确定我错过了什么。我试着添加了一个密钥,但我甚至不确定我需要在那里放什么,我认为这只是一个名称,指的是什么已经上传。 有人知道这个错误指的是什么以及我需要更改什么才能上传文件吗?任何帮助都将不胜感激。

  • 问题 如何限定上传文件的大小? Solution web.py 使用cgi 模块来解析用户的输入, 而 cgi 模块对最大输入大小有限制。 下面的代码限制了最大数据输入为 10MB. import cgi # Maximum input we will accept when REQUEST_METHOD is POST # 0 ==> unlimited input cgi.maxlen =

  • 是否可以使用azure sdk for java或azure sdk for net创建tomcat和MySQL/SqlServer服务,并以编程方式部署war文件? 我浏览了关于创建资源组和虚拟机的示例代码,但是没有找到关于在sdk中创建tomcat、sqlserver或MySQL的api。 如果这是不可能的,那么如何对Azure进行编程/自动部署?

  • 更新:为了将来的参考,亚马逊现在已经更新了询问时的文档。根据@Loren Segal在下面的评论:- 我们已经更正了最新预览版中的文档,以正确记录此参数。很抱歉搞砸了! 有人能帮我使用上传二进制文件吗?