当前位置: 首页 > news >正文

Aws S3上传优化

上传大约 3.4GB 的 JSON 文件,zip算法压缩后约为 395MB,上传至 S3 效率优化,有一些优化方案可以提高上传速率。下面是几种可能的优化方式,包括选择压缩算法、调整上传方式、以及其他可能的方案。

方案

1. 选择更好的压缩算法

压缩算法直接影响压缩比率和压缩/解压速度。对于你的数据,考虑到是 JSON 文件,可以尝试以下几种压缩算法:

a. Zstandard (zstd)
  • 特点:Zstandard 是一种高效的压缩算法,提供 更高的压缩比率更快的压缩/解压速度。它是目前最受欢迎的压缩算法之一,尤其适用于需要平衡压缩比和速度的场景。
  • 优势
    • 高压缩比:相比于 gzip 或 bzip2,Zstd 可以提供更高的压缩比。
    • 压缩速度:Zstd 提供了非常快的压缩速度,甚至在高压缩比时也能保持较快速度。
    • 支持字典压缩:Zstd 可以针对特定类型的数据(如 JSON)使用预训练的字典,以进一步提高压缩比。
  • 如何使用
    • 使用 zstd 工具压缩 JSON 文件,或者使用如 java-zstd 之类的 Java 库。
    • zstd 中,你可以通过调整压缩级别来平衡压缩率与速度,通常 level 19 以上会提供最优的压缩比。
b. Brotli
  • 特点:Brotli 是 Google 开发的压缩算法,通常压缩比率较高,但速度稍慢于 Zstd。
  • 优势
    • 高压缩比:Brotli 提供非常高的压缩比,尤其适合文本类文件(如 JSON)。
    • 支持 HTTP 压缩:在 web 应用中,Brotli 是一种推荐的压缩算法,适用于 HTTP 传输压缩。
  • 如何使用
    • 如果你关注最大压缩比,可以使用 Brotli,但可能会牺牲一定的速度。
    • Java 可以通过 brotli-java 库进行压缩。
c. Gzip
  • 特点:Gzip 是最常用的压缩格式,虽然压缩比和速度比 Zstd 和 Brotli 稍逊,但仍然是一个广泛应用的标准。
  • 优势
    • 高度兼容:几乎所有的工具和平台都支持 Gzip。
    • 较快的压缩速度,适合流式处理。
  • 如何使用
    • Gzip 可以通过 Java 的 java.util.zip.GZIPOutputStream 进行压缩,通常选择适中级别的压缩。
d. LZ4
  • 特点:LZ4 是一个超高速的压缩算法,压缩比不如 Zstd 或 Brotli 高,但它提供了极快的压缩和解压速度,适用于需要高吞吐量的场景。
  • 优势
    • 非常快的压缩/解压速度。
    • 适用于实时数据传输或非常频繁的压缩操作。

如何使用

- 适用于流式处理,如果你对上传时间有非常高的要求,可以考虑使用 LZ4。

2. 上传优化方案

压缩文件的上传到 S3,除了压缩算法外,上传方式也会影响性能。以下是一些优化上传速率的建议:

a. 分块上传(Multipart Upload)

对于大文件(如你 395MB 的压缩包),使用 S3 的 Multipart Upload 可以显著提高上传速度。

  • 分块上传:将大文件分割成多个较小的块(如 5MB 或更大的块),每个块并行上传,然后在服务器端合并。这种方式可以显著提高上传速率,尤其是网络带宽受限时。
  • 并行上传:上传多个文件或文件块时,确保使用多线程或并行任务来提升上传速率。
b. 优化 S3 配置
  • 选择合适的 S3 存储类型:对于频繁访问的文件,选择 S3 Standard 存储类型;对于长期存储不频繁访问的数据,可以选择 S3 GlacierS3 Intelligent-Tiering,这样能进一步优化成本。
  • 上传的区域选择:确保将文件上传至与用户或服务最接近的 AWS 区域。不同区域的网络带宽不同,选择一个低延迟、高带宽的区域将有助于提升上传速度。
c. 使用 AWS SDK 或 AWS CLI 上传
  • AWS SDK:使用 AWS 提供的 SDK(如 AWS SDK for Java)进行分块上传可以帮助管理并发任务,提升上传效率。
  • AWS CLI:如果使用命令行,aws s3 cpaws s3 sync 命令本身就支持分块上传,并且能自动优化上传过程。
aws s3 cp largefile.zip s3://yourbucket/ --storage-class STANDARD_IA --sse AES256 --multipart-chunk-size-mb 10
d. 压缩时减少冗余

在压缩时,尽量去除 JSON 文件中的冗余数据(如空格、换行符等),以便达到更高的压缩比。你可以在压缩前通过工具(如 jq)将 JSON 格式化处理为一个最小的单行格式。

cat *.json | jq -c . > compressed.json

3. 硬件和网络优化

  • 网络带宽:上传文件的速度受限于你服务器或本地网络的上传带宽。如果可能,尝试优化网络连接(例如使用更快的上传链路、避免网络瓶颈)。
  • 硬盘读写速度:确保压缩文件时,硬盘读写性能足够好,特别是使用 SSD 而非机械硬盘,以避免磁盘 I/O 成为瓶颈。

4. 云端优化

如果你通过中间服务器上传至 S3,考虑使用 AWS Direct Connect 或与 AWS 区域直接连接的高速网络线路,以避免互联网带宽限制。

5. 总结

  • 压缩算法选择:Zstandard(zstd)在提供高压缩比和高速压缩性能之间有很好的平衡,适合用于此类文件压缩。
  • 分块上传:通过 S3 的 Multipart Upload 功能,并行上传大文件,能显著提高上传速率。
  • 工具和网络优化:使用 AWS SDK、CLI,或者在压缩文件时去除冗余,进一步提升效率。

根据这些方案,你可以显著提升文件上传至 S3 的速度和效率。

实践

Apache Commons Compress

依赖

  • Maven:
<dependency><groupId>org.apache.commons</groupId><artifactId>commons-compress</artifactId><version>1.21</version>
</dependency>

压缩文件

首先,我们通过 CompressorStreamFactory 来根据指定的压缩算法(如 Brotli)压缩文件。

import org.apache.commons.compress.compressors.CompressorStreamFactory;
import org.apache.commons.compress.compressors.CompressorOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;public class CompressionExample {public static void main(String[] args) {String inputData = "This is some sample text to be compressed using Brotli.";String outputFile = "output.br";  // 输出为 Brotli 压缩文件try {// 创建输出流OutputStream fileOutputStream = new FileOutputStream(outputFile);CompressorStreamFactory factory = new CompressorStreamFactory();// 动态选择压缩算法(Brotli)try (CompressorOutputStream compressorOutputStream = factory.createCompressorOutputStream("brotli", fileOutputStream)) {compressorOutputStream.write(inputData.getBytes());// 文件流之间复制// 使用 IOUtils 工具类将输入流的数据写入到压缩输出流// IOUtils.copy(fileInputStream, lz4OutputStream);}System.out.println("File compressed to: " + outputFile);} catch (IOException | org.apache.commons.compress.compressors.CompressorException e) {e.printStackTrace();}}
}

解压缩文件

对于解压缩操作,我们使用 CompressorStreamFactory 来自动选择与压缩时相同的解压缩算法,并解压文件。

import org.apache.commons.compress.compressors.CompressorStreamFactory;
import org.apache.commons.compress.compressors.CompressorInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;public class DecompressionExample {public static void main(String[] args) {String inputFile = "output.br";  // 输入为 Brotli 压缩文件String outputFile = "decompressed.txt";  // 解压后的文件try {// 创建输入流InputStream fileInputStream = new FileInputStream(inputFile);CompressorStreamFactory factory = new CompressorStreamFactory();// 动态选择解压缩算法(Brotli)try (CompressorInputStream compressorInputStream = factory.createCompressorInputStream("brotli", fileInputStream)) {int byteRead;StringBuilder decompressedData = new StringBuilder();// 读取解压缩后的数据while ((byteRead = compressorInputStream.read()) != -1) {decompressedData.append((char) byteRead);}// 输出解压缩数据System.out.println("Decompressed data: " + decompressedData.toString());}} catch (IOException | org.apache.commons.compress.compressors.CompressorException e) {e.printStackTrace();}}
}

其他类库

zstd

要在 Java 中使用 Zstandard (zstd) 进行压缩和解压缩,你可以使用第三方库,例如 zstd-jni,它是一个基于 JNI 的 Java 实现,允许你在 Java 中高效地使用 Zstandard 算法。

1. 添加依赖

如果你使用的是 Maven,可以在 pom.xml 中添加以下依赖:

<dependency><groupId>com.github.luben</groupId><artifactId>zstd-jni</artifactId><version>1.5.2-1</version>
</dependency>

2. Zstandard 压缩与解压缩案例

以下是一个简单的 Java 示例,展示如何使用 zstd-jni 进行文件的压缩和解压缩。

a. 压缩文件
import com.github.luben.zstd.ZstdOutputStream;import java.io.*;
import java.nio.file.Files;public class ZstdCompressExample {public static void main(String[] args) throws IOException {String inputFile = "input.json";String outputFile = "output.zst";// 创建输入文件流try (InputStream in = new FileInputStream(inputFile);OutputStream out = new FileOutputStream(outputFile);ZstdOutputStream zstdOut = new ZstdOutputStream(out)) {// 进行压缩byte[] buffer = new byte[8192];int bytesRead;while ((bytesRead = in.read(buffer)) != -1) {zstdOut.write(buffer, 0, bytesRead);}}System.out.println("File compressed successfully: " + outputFile);}
}
  • 解释
    • 通过 ZstdOutputStream 将输入文件流压缩后写入到输出文件中。
    • 使用 8KB 缓冲区来提高处理效率。
b. 解压缩文件
import com.github.luben.zstd.ZstdInputStream;import java.io.*;public class ZstdDecompressExample {public static void main(String[] args) throws IOException {String inputFile = "output.zst";String outputFile = "decompressed.json";// 创建输入文件流try (InputStream in = new FileInputStream(inputFile);ZstdInputStream zstdIn = new ZstdInputStream(in);OutputStream out = new FileOutputStream(outputFile)) {// 进行解压缩byte[] buffer = new byte[8192];int bytesRead;while ((bytesRead = zstdIn.read(buffer)) != -1) {out.write(buffer, 0, bytesRead);}}System.out.println("File decompressed successfully: " + outputFile);}
}
  • 解释
    • 通过 ZstdInputStream 读取压缩文件并解压,然后将解压后的数据写入输出文件中。

3. 压缩和解压缩字节数组(内存中的数据)

如果你不想直接操作文件,也可以对字节数组进行压缩和解压缩。

a. 压缩字节数组
import com.github.luben.zstd.Zstd;import java.io.IOException;
import java.util.Arrays;public class ZstdByteArrayCompressExample {public static void main(String[] args) throws IOException {byte[] inputData = "This is a sample data to be compressed.".getBytes();// 使用 Zstandard 压缩字节数组byte[] compressedData = Zstd.compress(inputData);System.out.println("Original size: " + inputData.length);System.out.println("Compressed size: " + compressedData.length);}
}
b. 解压缩字节数组
import com.github.luben.zstd.Zstd;import java.io.IOException;public class ZstdByteArrayDecompressExample {public static void main(String[] args) throws IOException {byte[] compressedData = "This is a sample data to be compressed.".getBytes(); // 假设这已经是压缩过的数据// 使用 Zstandard 解压字节数组byte[] decompressedData = Zstd.decompress(compressedData, 1000);  // 1000 是最大预期大小System.out.println("Decompressed data: " + new String(decompressedData));}
}

4. 优化压缩级别

你还可以通过设置压缩级别来平衡压缩率和压缩速度。Zstandard 提供了多个级别(1 到 22),数字越大,压缩比越高,但速度较慢。

import com.github.luben.zstd.Zstd;import java.io.IOException;public class ZstdCompressExample {public static void main(String[] args) throws IOException {byte[] inputData = "This is a sample data to be compressed.".getBytes();// 使用级别 3 进行压缩byte[] compressedData = Zstd.compress(inputData, 3);System.out.println("Original size: " + inputData.length);System.out.println("Compressed size: " + compressedData.length);}
}

5. 总结

  • zstd-jni 是一个高效的 Zstandard 实现,适用于压缩和解压大文件或字节数组。
  • 压缩和解压过程支持文件和内存中的数据,灵活性较高。
  • 通过设置压缩级别,可以在压缩比和压缩速度之间找到平衡。
  • 你可以结合压缩和多线程来提升上传速度,尤其是在上传到 S3 这类云存储时。

通过这些方法,你可以在 Java 项目中高效地使用 Zstandard 来处理压缩和解压缩,提升数据传输效率。

Brotli

Google 的 Brotli Java 绑定可以通过 Brotli 官方提供的 Java 库来使用,它是由 Google 维护的,具有更活跃的社区支持和更多的更新。这个库是直接通过 com.google 包提供的,你可以使用它来进行 Brotli 压缩和解压缩。

下面是如何使用 Google 的 Brotli Java 绑定 来进行压缩和解压缩操作的示例。

1. 添加依赖

你可以通过以下方式将 Brotli 添加到你的项目中。

Maven

pom.xml 中添加依赖:

<dependency><groupId>com.google.code.findbugs</groupId><artifactId>jsr305</artifactId><version>3.0.2</version>
</dependency>
<dependency><groupId>com.google.brotli</groupId><artifactId>brotli</artifactId><version>1.7.0</version>
</dependency>

2. 使用 Brotli 进行压缩和解压缩

以下是压缩和解压缩文件的示例。

压缩数据
import com.google.brotli.encoder.BrotliOutputStream;import java.io.*;public class BrotliCompressExample {public static void main(String[] args) {String inputFilePath = "input.txt";  // 输入文件路径String outputFilePath = "output.br"; // 输出压缩文件路径try {// 读取输入文件File inputFile = new File(inputFilePath);byte[] inputData = readFile(inputFile);// 压缩数据byte[] compressedData = compress(inputData);// 将压缩数据写入输出文件writeFile(outputFilePath, compressedData);System.out.println("Compression complete: " + outputFilePath);} catch (IOException e) {e.printStackTrace();}}// 读取文件内容为字节数组public static byte[] readFile(File file) throws IOException {try (InputStream is = new FileInputStream(file);ByteArrayOutputStream buffer = new ByteArrayOutputStream()) {byte[] chunk = new byte[1024];int bytesRead;while ((bytesRead = is.read(chunk)) != -1) {buffer.write(chunk, 0, bytesRead);}return buffer.toByteArray();}}// 使用 Brotli 压缩数据public static byte[] compress(byte[] input) throws IOException {try (ByteArrayOutputStream baos = new ByteArrayOutputStream();BrotliOutputStream brotliOut = new BrotliOutputStream(baos)) {brotliOut.write(input);brotliOut.flush();return baos.toByteArray();}}// 写数据到文件public static void writeFile(String filePath, byte[] data) throws IOException {try (FileOutputStream fos = new FileOutputStream(filePath)) {fos.write(data);}}
}
解压缩数据
import com.google.brotli.decoder.BrotliInputStream;import java.io.*;public class BrotliDecompressExample {public static void main(String[] args) {String inputFilePath = "output.br";  // 输入文件路径(压缩文件)String outputFilePath = "decompressed.txt"; // 输出解压文件路径try {// 解压缩数据byte[] decompressedData = decompress(new File(inputFilePath));// 将解压缩的数据写入文件writeFile(outputFilePath, decompressedData);System.out.println("Decompression complete: " + outputFilePath);} catch (IOException e) {e.printStackTrace();}}// 使用 Brotli 解压缩数据public static byte[] decompress(File inputFile) throws IOException {try (InputStream is = new FileInputStream(inputFile);BrotliInputStream brotliIn = new BrotliInputStream(is);ByteArrayOutputStream baos = new ByteArrayOutputStream()) {byte[] buffer = new byte[1024];int bytesRead;while ((bytesRead = brotliIn.read(buffer)) != -1) {baos.write(buffer, 0, bytesRead);}return baos.toByteArray();}}// 写数据到文件public static void writeFile(String filePath, byte[] data) throws IOException {try (FileOutputStream fos = new FileOutputStream(filePath)) {fos.write(data);}}
}

3. 代码解析

  • 压缩BrotliOutputStream 用于压缩数据。你只需要通过 write() 将数据写入流中,然后使用 flush() 提交压缩的数据。
  • 解压缩BrotliInputStream 用于读取压缩数据并解压。数据通过 read() 方法被读取并解压到输出流中,最终可以通过 ByteArrayOutputStream 获取解压后的数据。
  • 文件操作:我们使用 FileInputStreamFileOutputStream 来处理文件的读取和写入。

4. 性能与配置

Brotli 算法提供了非常高效的压缩率,尤其适合用于 Web 内容压缩,但其压缩速度相对较慢。你可以调整压缩级别来平衡压缩率与性能:

  • 压缩级别:通过 BrotliOutputStream 构造函数的第二个参数设置压缩级别,范围是 0 到 11,0 表示最快但压缩率低,11 表示最慢但压缩率高。

示例:设置压缩级别为 5:

BrotliOutputStream brotliOut = new BrotliOutputStream(baos, 5);

5. 总结

Google 的 Brotli Java 绑定提供了 BrotliInputStreamBrotliOutputStream 类,分别用于解压和压缩 Brotli 格式的文件。这个库比 Brotli4j 更活跃,且得到了 Google 官方的支持。通过调整压缩级别,你可以在压缩率和速度之间找到合适的平衡。

LZ4

在 Java 中使用 LZ4 压缩算法,可以通过 lz4-java 库,它是一个对 LZ4 算法的 Java 实现。LZ4 以其超高速压缩和解压速度著称,适用于需要高吞吐量的场景。以下是如何在 Java 中使用 LZ4 来压缩和解压数据的完整示例。

1. 添加依赖

首先,确保将 lz4-java 添加到你的项目依赖中。

Maven

pom.xml 中添加以下依赖:

<dependency><groupId>net.jpountz.lz4</groupId><artifactId>lz4</artifactId><version>1.8.0</version>
</dependency>

2. 使用 LZ4 压缩和解压缩

以下是一个基本的示例,展示了如何使用 LZ4 压缩和解压缩文件内容。

压缩数据
import net.jpountz.lz4.LZ4BlockOutputStream;
import net.jpountz.lz4.LZ4Factory;import java.io.*;public class LZ4CompressExample {public static void main(String[] args) {String inputFilePath = "input.txt";  // 输入文件路径String outputFilePath = "output.lz4"; // 输出压缩文件路径try {// 读取输入文件File inputFile = new File(inputFilePath);byte[] inputData = readFile(inputFile);// 压缩数据byte[] compressedData = compress(inputData);// 将压缩数据写入输出文件writeFile(outputFilePath, compressedData);System.out.println("Compression complete: " + outputFilePath);} catch (IOException e) {e.printStackTrace();}}// 读取文件内容为字节数组public static byte[] readFile(File file) throws IOException {try (InputStream is = new FileInputStream(file);ByteArrayOutputStream buffer = new ByteArrayOutputStream()) {byte[] chunk = new byte[1024];int bytesRead;while ((bytesRead = is.read(chunk)) != -1) {buffer.write(chunk, 0, bytesRead);}return buffer.toByteArray();}}// 使用 LZ4 压缩数据public static byte[] compress(byte[] input) throws IOException {LZ4Factory factory = LZ4Factory.fastestInstance();ByteArrayOutputStream baos = new ByteArrayOutputStream();try (LZ4BlockOutputStream lz4Out = new LZ4BlockOutputStream(baos, factory.fastestCompressor())) {lz4Out.write(input);lz4Out.flush();}return baos.toByteArray();}// 写数据到文件public static void writeFile(String filePath, byte[] data) throws IOException {try (FileOutputStream fos = new FileOutputStream(filePath)) {fos.write(data);}}
}
解压缩数据
import net.jpountz.lz4.LZ4BlockInputStream;
import net.jpountz.lz4.LZ4Factory;import java.io.*;public class LZ4DecompressExample {public static void main(String[] args) {String inputFilePath = "output.lz4";  // 输入文件路径(压缩文件)String outputFilePath = "decompressed.txt"; // 输出解压文件路径try {// 解压缩数据byte[] decompressedData = decompress(new File(inputFilePath));// 将解压缩的数据写入文件writeFile(outputFilePath, decompressedData);System.out.println("Decompression complete: " + outputFilePath);} catch (IOException e) {e.printStackTrace();}}// 使用 LZ4 解压缩数据public static byte[] decompress(File inputFile) throws IOException {try (InputStream is = new FileInputStream(inputFile);LZ4BlockInputStream lz4In = new LZ4BlockInputStream(is)) {ByteArrayOutputStream baos = new ByteArrayOutputStream();byte[] buffer = new byte[1024];int bytesRead;while ((bytesRead = lz4In.read(buffer)) != -1) {baos.write(buffer, 0, bytesRead);}return baos.toByteArray();}}// 写数据到文件public static void writeFile(String filePath, byte[] data) throws IOException {try (FileOutputStream fos = new FileOutputStream(filePath)) {fos.write(data);}}
}

3. 代码解析

  • 压缩LZ4BlockOutputStream 用于将数据写入压缩流。你可以通过传入 LZ4Factory.fastestCompressor() 来选择最快的压缩器。压缩后的字节数据可以被写入到 ByteArrayOutputStream,并最终得到压缩后的数据。
  • 解压缩LZ4BlockInputStream 用于从压缩流中读取数据并进行解压。读取后,数据会被写入到 ByteArrayOutputStream,最终得到解压后的字节数据。
  • 性能:LZ4 是一种非常快速的压缩算法,它优化了 CPU 使用率,并且能够在压缩速度和压缩比之间取得较好的平衡。fastestCompressor() 是最快的压缩方法,适用于需要快速压缩的场景。

4. 压缩级别

LZ4 并不像其他压缩算法(如 Zstd)那样支持多个压缩级别。它的设计重点是压缩速度,因此它的压缩速度相对较快,但压缩比没有像 Zstd 那么高。如果你需要更高的压缩比,Zstd 或 Brotli 可能更适合。不过,对于需要极快压缩/解压速度的场景,LZ4 是一个非常好的选择。

5. 总结

  • LZ4 的特点:LZ4 是一个高性能、低延迟的压缩算法,适合处理对速度要求较高的场景,尤其是流式数据和大数据处理。
  • 压缩方式:Java 中通过 LZ4BlockOutputStreamLZ4BlockInputStream 来处理文件压缩与解压缩。对于内存中的字节数组,可以使用 LZ4CompressorLZ4FastDecompressor
  • 性能:LZ4 提供了非常快的压缩和解压缩速度,虽然压缩比相对较低,但仍适合用于大部分实时应用场景。

通过这种方式,你可以在 Java 中高效地使用 LZ4 压缩和解压缩数据,提升数据传输和存储的效率。

S3分块上传

分块上传(Multipart Upload)是 Amazon S3 的一个功能,允许将大文件分为多个部分进行上传,从而提高上传效率,并支持在上传过程中断点续传。在 AWS SDK for Java 中,你可以使用 TransferManager 来实现分块上传,或者使用 AmazonS3 提供的原生 initiateMultipartUpload 方法进行自定义实现。

分块上传的步骤

  1. 初始化上传:调用 initiateMultipartUpload 方法开始一个分块上传操作。
  2. 上传各个部分:将文件分割成多个块并上传。
  3. 完成上传:调用 completeMultipartUpload 来完成上传。

使用 AWS SDK for Java 实现分块上传的示例

1. Maven 依赖

确保你的 Maven 项目中包含了 AWS SDK for Java 的相关依赖:

<dependency><groupId>com.amazonaws</groupId><artifactId>aws-java-sdk-s3</artifactId><version>2.20.1</version> <!-- 请使用最新版本 -->
</dependency>

2. 分块上传代码示例

下面是一个分块上传的代码示例,使用 AmazonS3TransferManager 进行分块上传。

import com.amazonaws.AmazonServiceException;
import com.amazonaws.auth.profile.ProfileCredentialsProvider;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import com.amazonaws.services.s3.model.*;import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.List;public class S3MultipartUpload {private static final String BUCKET_NAME = "your-bucket-name"; // 目标S3桶名private static final String OBJECT_KEY = "your-object-key"; // 目标文件在S3的键(路径)public static void main(String[] args) throws IOException {// 初始化AmazonS3客户端AmazonS3 s3Client = AmazonS3ClientBuilder.standard().withCredentials(new ProfileCredentialsProvider()) // 使用配置文件中的凭证.build();// 文件路径File file = new File("path-to-large-file");// 分块大小,5MB是最小的分块大小long partSize = 5 * 1024 * 1024; // 获取文件大小long fileSize = file.length();// 初始化分块上传InitiateMultipartUploadRequest initRequest = new InitiateMultipartUploadRequest(BUCKET_NAME, OBJECT_KEY);InitiateMultipartUploadResult initResponse = s3Client.initiateMultipartUpload(initRequest);String uploadId = initResponse.getUploadId();// 按照分块大小分割文件并上传List<PartETag> partETags = new ArrayList<>();try {// 分块上传for (long i = 0; i < fileSize; i += partSize) {long size = Math.min(partSize, fileSize - i);UploadPartRequest uploadRequest = new UploadPartRequest().withBucketName(BUCKET_NAME).withKey(OBJECT_KEY).withUploadId(uploadId).withPartNumber((int) (i / partSize) + 1).withFileOffset(i).withFile(file).withPartSize(size);// 上传分块UploadPartResult uploadPartResult = s3Client.uploadPart(uploadRequest);partETags.add(uploadPartResult.getPartETag());System.out.println("Uploaded part " + (i / partSize + 1));}// 完成上传CompleteMultipartUploadRequest completeRequest = new CompleteMultipartUploadRequest(BUCKET_NAME, OBJECT_KEY, uploadId, partETags);s3Client.completeMultipartUpload(completeRequest);System.out.println("File uploaded successfully!");} catch (AmazonServiceException e) {// 如果上传失败,取消上传s3Client.abortMultipartUpload(new AbortMultipartUploadRequest(BUCKET_NAME, OBJECT_KEY, uploadId));e.printStackTrace();}}
}

3. 代码说明

  • 初始化上传(**initiateMultipartUpload**:通过 InitiateMultipartUploadRequest 创建一个新的上传任务,并返回一个 uploadId,这个 ID 用于后续分块上传和完成上传。
  • 分块上传(**uploadPart**:通过 UploadPartRequest 来上传每个文件块。withFileOffset 表示文件上传的起始偏移位置,withPartSize 用于指定每个块的大小。
  • 完成上传(**completeMultipartUpload**:所有部分上传成功后,使用 CompleteMultipartUploadRequest 来完成分块上传,所有上传的部分会被合并成一个完整的文件。
  • 错误处理(**abortMultipartUpload**:在上传过程中如果发生异常(例如服务端错误),我们调用 abortMultipartUpload 来取消上传,并清理资源。

4. 注意事项

  • 分块大小:AWS 对分块上传有一定的要求。每个部分必须至少为 5MB,最后一个部分可以小于 5MB。可以根据文件的大小选择合理的分块大小。
  • 上传过程中的错误:如果上传失败,记得调用 abortMultipartUpload 来中止上传,避免留下未完成的部分。
  • 凭证管理:本示例使用了 ProfileCredentialsProvider,你也可以选择其他凭证提供方式,例如环境变量或硬编码凭证,但不推荐硬编码。

5. **更高效的方式:使用 ****TransferManager**

对于一些应用场景,你可以使用 TransferManager 进行更加高效和便捷的分块上传。TransferManager 是 AWS SDK 提供的高级 API,自动处理分块上传和下载、进度报告等功能。以下是使用 TransferManager 实现分块上传的示例:

使用 TransferManager 实现分块上传
import com.amazonaws.auth.profile.ProfileCredentialsProvider;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import com.amazonaws.services.s3.model.*;
import com.amazonaws.services.s3.transfer.TransferManager;
import com.amazonaws.services.s3.transfer.Upload;import java.io.File;public class TransferManagerExample {private static final String BUCKET_NAME = "your-bucket-name";private static final String OBJECT_KEY = "your-object-key";public static void main(String[] args) {// 初始化S3客户端和TransferManagerAmazonS3 s3Client = AmazonS3ClientBuilder.standard().withCredentials(new ProfileCredentialsProvider()).build();TransferManager transferManager = TransferManagerBuilder.standard().s3Client(s3Client).build();// 创建文件对象File file = new File("path-to-large-file");// 开始分块上传Upload upload = transferManager.upload(BUCKET_NAME, OBJECT_KEY, file);try {// 等待上传完成upload.waitForCompletion();System.out.println("Upload completed!");} catch (Exception e) {e.printStackTrace();}}
}

在这个示例中,TransferManager 会自动处理文件分割、上传和合并的工作,你不需要手动拆分文件和上传每一部分。

6. 总结

  • 分块上传:AWS S3 提供了分块上传功能,适用于上传大文件。你可以使用 AmazonS3 的原生方法或者 TransferManager 来简化这个过程。
  • **TransferManager**:是 AWS SDK 提供的更高层次的 API,简化了分块上传的过程,自动处理了上传任务和块的管理。
  • 错误处理:上传过程中如果发生异常,记得调用 abortMultipartUpload 来清理未完成的上传任务。

选择哪种方式取决于你的需求,如果你需要更多控制和自定义分块上传的行为,可以使用 AmazonS3 的原生方法;如果你希望快速实现且自动处理所有细节,TransferManager 是一个更方便的选择。

API选择建议

文件大小

  • 小文件(<100MB):S3 SDK 原生 API。
  • 中型文件(100MB~500MB):S3 Transfer Manager,享受分块传输的性能优化。
  • 大文件(>500MB):Transfer Manager 或者 AWS CLI。

性能对比

工具适用范围优势劣势
S3 Transfer Manager100MB~GB+并发传输、分块优化、高效、异步支持需要更多依赖,初始化稍复杂
原生 S3 API小于 500MB简单直接,无需额外配置无分块传输,性能有限
AWS CLI小型/大型文件易用,后台优化传输性能需要使用命令行,无法嵌入 Java 项目

相关文章:

  • Spring MVC @RequestHeader 注解怎么用?
  • 第5篇:EggJS中间件开发与实战应用
  • 【学习笔记】深入理解Java虚拟机学习笔记——第2章 Java内存区域与内存溢出异常
  • JavaScript性能优化实战之运行时性能优化
  • gRPC学习笔记记录以及整合gin开发
  • 云原生后端:构建高效、可扩展的现代后端架构
  • JVM——JVM 是如何执行方法调用的?
  • NFS 快速开始
  • React的patch流程
  • MySQL基本查询(二)
  • Python清空Word段落样式的方法
  • 【iOS】类与对象底层探索
  • 2025年- H20-Lc128-240. 搜索二维矩阵 II(矩阵)---java版
  • Qt 项目代码解释(4)
  • 【点对点协议(PPP)全解析】从原理到工程实践
  • PostgreSQL:pgJDBC 下载和安装
  • DeepSeek玄学指令大全
  • Redis TLS 加密对性能的影响分析
  • 机器学习中的学习率及其衰减方法全面解析
  • 【KWDB 创作者计划】技术解读:多模架构、高效时序数据处理与分布式实现
  • 中虎跳峡封闭仍有游客逆行打卡,景区:专人值守防意外
  • 澳大利亚大选今日投票:聚焦生活成本与“特朗普问题”
  • 科普|“小石头,大麻烦”,出现输尿管结石如何应对?
  • 张建华评《俄国和法国》|埃莲娜·唐科斯的俄法关系史研究
  • 五一当天1372对新人在沪喜结连理,涉外婚姻登记全市铺开
  • Meta一季度净利增长三成:上调全年资本支出,受关税影响亚洲出口电商广告支出减少