From 13d945172ffdd31df591e9fd3ec2e3c24ab7c9c9 Mon Sep 17 00:00:00 2001 From: Afly Date: Mon, 24 Jul 2023 20:24:42 +0800 Subject: [PATCH 1/4] =?UTF-8?q?REPORT-100817=20fix:=20s3=E6=8F=92=E4=BB=B6?= =?UTF-8?q?=E5=AF=B9=E4=BA=8E=E5=88=86=E7=89=87=E4=B8=8A=E4=BC=A0=E7=9A=84?= =?UTF-8?q?=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../repository/core/S3ResourceRepository.java | 68 +++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/src/main/java/com/fanruan/fs/s3/repository/core/S3ResourceRepository.java b/src/main/java/com/fanruan/fs/s3/repository/core/S3ResourceRepository.java index 21e5d7b..e4b0a2e 100644 --- a/src/main/java/com/fanruan/fs/s3/repository/core/S3ResourceRepository.java +++ b/src/main/java/com/fanruan/fs/s3/repository/core/S3ResourceRepository.java @@ -7,25 +7,34 @@ import com.amazonaws.auth.BasicAWSCredentials; import com.amazonaws.client.builder.AwsClientBuilder; import com.amazonaws.services.s3.AmazonS3; import com.amazonaws.services.s3.AmazonS3ClientBuilder; +import com.amazonaws.services.s3.model.CompleteMultipartUploadRequest; import com.amazonaws.services.s3.model.DeleteObjectsRequest; import com.amazonaws.services.s3.model.GetObjectRequest; +import com.amazonaws.services.s3.model.InitiateMultipartUploadRequest; +import com.amazonaws.services.s3.model.InitiateMultipartUploadResult; import com.amazonaws.services.s3.model.ListObjectsRequest; import com.amazonaws.services.s3.model.ObjectListing; import com.amazonaws.services.s3.model.ObjectMetadata; +import com.amazonaws.services.s3.model.PartETag; import com.amazonaws.services.s3.model.PutObjectRequest; import com.amazonaws.services.s3.model.S3Object; import com.amazonaws.services.s3.model.S3ObjectSummary; +import com.amazonaws.services.s3.model.UploadPartRequest; +import com.amazonaws.services.s3.model.UploadPartResult; import com.amazonaws.util.IOUtils; import com.fanruan.api.log.LogKit; import com.fanruan.api.util.StringKit; import com.fr.io.repository.FineFileEntry; import com.fr.io.repository.base.BaseResourceRepository; +import com.fr.io.utils.ResourceIOUtils; +import com.fr.log.FineLoggerFactory; import com.fr.stable.Filter; import com.fr.stable.StringUtils; import com.fr.third.org.apache.commons.io.output.NullOutputStream; import com.fr.workspace.resource.ResourceIOException; import java.io.ByteArrayInputStream; +import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.net.URLConnection; @@ -41,6 +50,10 @@ public class S3ResourceRepository extends BaseResourceRepository { private static final int PAGE_SIZE = 1000; + private static final int PART_SIZE = 5 * 1024 * 1024; + + private static final int MULTIPART_UPLOAD_LIMIT = 4 * PART_SIZE; + private static final String DELIMITER = "/"; public static final String HTTP = "http:"; @@ -158,6 +171,61 @@ public class S3ResourceRepository extends BaseResourceRepository { s3.putObject(bucket, path, new ByteArrayInputStream(data), metadata); } + @Override + public void write(String path, InputStream inputStream) throws ResourceIOException { + long dataLength = 0; + try { + dataLength = inputStream.available(); + } catch (IOException e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + } + //超过一定大小才使用分片上传,小文件来说,网络传输时间可能较短,且上传失败的风险相对较低。 + //在网络稳定的情况下,使用分片上传可能没有太多的优势,反而增加了额外开销和复杂性 + if (dataLength > MULTIPART_UPLOAD_LIMIT) { + try { + // Step 1: 初始化分片上传 + InitiateMultipartUploadRequest initRequest = new InitiateMultipartUploadRequest(bucket, path); + InitiateMultipartUploadResult initResponse = s3.initiateMultipartUpload(initRequest); + String uploadId = initResponse.getUploadId(); + + // Step 2: 分片上传文件 + List partETags = new ArrayList<>(); + long position = 0; + + for (int partNumber = 1; position < dataLength; partNumber++) { + // 最后一个分片可能小于5MB + long partSizeBytes = Math.min(PART_SIZE, dataLength - position); + byte[] bytes = new byte[(int) partSizeBytes]; + inputStream.read(bytes); + + // 创建上传请求 + UploadPartRequest uploadRequest = new UploadPartRequest() + .withBucketName(bucket) + .withKey(path) + .withUploadId(uploadId) + .withPartNumber(partNumber) + .withInputStream(new ByteArrayInputStream(bytes)) + .withPartSize(partSizeBytes); + + // 上传分片 + UploadPartResult uploadResult = s3.uploadPart(uploadRequest); + partETags.add(uploadResult.getPartETag()); + + position += partSizeBytes; + } + + // Step 3: 完成分片上传 + CompleteMultipartUploadRequest compRequest = new CompleteMultipartUploadRequest(bucket, path, uploadId, partETags); + s3.completeMultipartUpload(compRequest); + } catch (IOException e) { + throw new ResourceIOException(e); + } finally { + ResourceIOUtils.close(inputStream); + } + } else { + super.write(path, inputStream); + } + } @Override public boolean createFile(String path) { From 66beccd286fd44257f38be2620302227a0ef5d1a Mon Sep 17 00:00:00 2001 From: Afly Date: Mon, 7 Aug 2023 13:55:30 +0800 Subject: [PATCH 2/4] =?UTF-8?q?REPORT-102146=20fix:=20isDirectory=E6=96=B9?= =?UTF-8?q?=E6=B3=95=E6=9F=90=E4=BA=9B=E5=9C=BA=E6=99=AF=E5=88=A4=E6=96=AD?= =?UTF-8?q?=E4=B8=8D=E6=AD=A3=E7=A1=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../repository/core/S3ResourceRepository.java | 21 ++++++++----------- 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/fanruan/fs/s3/repository/core/S3ResourceRepository.java b/src/main/java/com/fanruan/fs/s3/repository/core/S3ResourceRepository.java index e4b0a2e..6576e5b 100644 --- a/src/main/java/com/fanruan/fs/s3/repository/core/S3ResourceRepository.java +++ b/src/main/java/com/fanruan/fs/s3/repository/core/S3ResourceRepository.java @@ -399,19 +399,16 @@ public class S3ResourceRepository extends BaseResourceRepository { @Override public boolean isDirectory(String path) { - - if (path.endsWith(DELIMITER) && exist(path)) { - return true; - } - ObjectListing listing = s3.listObjects(bucket, path); - if (listing.getObjectSummaries().isEmpty()) { - return false; - } - if (listing.getObjectSummaries().size() > 1) { - return true; + if (path.endsWith(DELIMITER)) { + return exist(path); } else { - S3ObjectSummary summary = listing.getObjectSummaries().get(0); - return !StringKit.equals(listing.getPrefix(), summary.getKey()); + ObjectListing listing = s3.listObjects(bucket, path); + List objectSummaries = listing.getObjectSummaries(); + if (objectSummaries.isEmpty()) { + return false; + } + String dirFormat = path + DELIMITER; + return objectSummaries.stream().anyMatch(s3ObjectSummary -> StringUtils.equals(s3ObjectSummary.getKey(), dirFormat)); } } From d762e6348310dc3c35e4e4cad90223ae143249e3 Mon Sep 17 00:00:00 2001 From: Afly Date: Mon, 7 Aug 2023 14:02:20 +0800 Subject: [PATCH 3/4] =?UTF-8?q?JSY-28624=20fix:=20=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E4=B8=8B=E5=88=86=E7=89=87=E4=B8=8A=E4=BC=A0=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../repository/core/S3ResourceRepository.java | 117 ++++++++---------- 1 file changed, 55 insertions(+), 62 deletions(-) diff --git a/src/main/java/com/fanruan/fs/s3/repository/core/S3ResourceRepository.java b/src/main/java/com/fanruan/fs/s3/repository/core/S3ResourceRepository.java index 6576e5b..105cccb 100644 --- a/src/main/java/com/fanruan/fs/s3/repository/core/S3ResourceRepository.java +++ b/src/main/java/com/fanruan/fs/s3/repository/core/S3ResourceRepository.java @@ -27,7 +27,6 @@ import com.fanruan.api.util.StringKit; import com.fr.io.repository.FineFileEntry; import com.fr.io.repository.base.BaseResourceRepository; import com.fr.io.utils.ResourceIOUtils; -import com.fr.log.FineLoggerFactory; import com.fr.stable.Filter; import com.fr.stable.StringUtils; import com.fr.third.org.apache.commons.io.output.NullOutputStream; @@ -52,7 +51,7 @@ public class S3ResourceRepository extends BaseResourceRepository { private static final int PART_SIZE = 5 * 1024 * 1024; - private static final int MULTIPART_UPLOAD_LIMIT = 4 * PART_SIZE; + private static final int MULTIPART_UPLOAD_LIMIT = 20 * PART_SIZE; private static final String DELIMITER = "/"; public static final String HTTP = "http:"; @@ -155,75 +154,69 @@ public class S3ResourceRepository extends BaseResourceRepository { @Override public void write(String path, byte[] data) { - ObjectMetadata metadata; - try { - metadata = s3.getObjectMetadata(bucket, path); - } catch (Exception e) { - metadata = new ObjectMetadata(); - String mimeType = URLConnection.guessContentTypeFromName(path); - if (mimeType != null) { - metadata.setContentType(mimeType); + int length = data.length; + if (length > MULTIPART_UPLOAD_LIMIT) { + multipartUpload(path, new ByteArrayInputStream(data)); + } else { + ObjectMetadata metadata; + try { + metadata = s3.getObjectMetadata(bucket, path); + } catch (Exception e) { + metadata = new ObjectMetadata(); + String mimeType = URLConnection.guessContentTypeFromName(path); + if (mimeType != null) { + metadata.setContentType(mimeType); + } } + if (metadata != null) { + metadata.setContentLength(length); + } + s3.putObject(bucket, path, new ByteArrayInputStream(data), metadata); } - if (metadata != null) { - metadata.setContentLength(data.length); - } - s3.putObject(bucket, path, new ByteArrayInputStream(data), metadata); } @Override public void write(String path, InputStream inputStream) throws ResourceIOException { - long dataLength = 0; + multipartUpload(path, inputStream); + } + + private void multipartUpload(String path, InputStream inputStream) { try { - dataLength = inputStream.available(); - } catch (IOException e) { - FineLoggerFactory.getLogger().error(e.getMessage(), e); - } - //超过一定大小才使用分片上传,小文件来说,网络传输时间可能较短,且上传失败的风险相对较低。 - //在网络稳定的情况下,使用分片上传可能没有太多的优势,反而增加了额外开销和复杂性 - if (dataLength > MULTIPART_UPLOAD_LIMIT) { - try { - // Step 1: 初始化分片上传 - InitiateMultipartUploadRequest initRequest = new InitiateMultipartUploadRequest(bucket, path); - InitiateMultipartUploadResult initResponse = s3.initiateMultipartUpload(initRequest); - String uploadId = initResponse.getUploadId(); - - // Step 2: 分片上传文件 - List partETags = new ArrayList<>(); - long position = 0; - - for (int partNumber = 1; position < dataLength; partNumber++) { - // 最后一个分片可能小于5MB - long partSizeBytes = Math.min(PART_SIZE, dataLength - position); - byte[] bytes = new byte[(int) partSizeBytes]; - inputStream.read(bytes); - - // 创建上传请求 - UploadPartRequest uploadRequest = new UploadPartRequest() - .withBucketName(bucket) - .withKey(path) - .withUploadId(uploadId) - .withPartNumber(partNumber) - .withInputStream(new ByteArrayInputStream(bytes)) - .withPartSize(partSizeBytes); - - // 上传分片 - UploadPartResult uploadResult = s3.uploadPart(uploadRequest); - partETags.add(uploadResult.getPartETag()); - - position += partSizeBytes; - } + // Step 1: 初始化分片上传 + InitiateMultipartUploadRequest initRequest = new InitiateMultipartUploadRequest(bucket, path); + InitiateMultipartUploadResult initResponse = s3.initiateMultipartUpload(initRequest); + String uploadId = initResponse.getUploadId(); + + // Step 2: 分片上传文件 + List partETags = new ArrayList<>(); + byte[] buffer = new byte[PART_SIZE]; + int bytesRead; + int partNumber = 1; + + while ((bytesRead = inputStream.read(buffer)) > 0) { + // 创建上传请求 + UploadPartRequest uploadRequest = new UploadPartRequest() + .withBucketName(bucket) + .withKey(path) + .withUploadId(uploadId) + .withPartNumber(partNumber) + .withInputStream(new ByteArrayInputStream(buffer, 0, bytesRead)) + .withPartSize(bytesRead); - // Step 3: 完成分片上传 - CompleteMultipartUploadRequest compRequest = new CompleteMultipartUploadRequest(bucket, path, uploadId, partETags); - s3.completeMultipartUpload(compRequest); - } catch (IOException e) { - throw new ResourceIOException(e); - } finally { - ResourceIOUtils.close(inputStream); + // 上传分片 + UploadPartResult uploadResult = s3.uploadPart(uploadRequest); + partETags.add(uploadResult.getPartETag()); + + partNumber++; } - } else { - super.write(path, inputStream); + + // Step 3: 完成分片上传 + CompleteMultipartUploadRequest compRequest = new CompleteMultipartUploadRequest(bucket, path, uploadId, partETags); + s3.completeMultipartUpload(compRequest); + } catch (IOException e) { + throw new ResourceIOException(e); + } finally { + ResourceIOUtils.close(inputStream); } } From 3232e03cbdf1a56e57cdae46515c5c78eaf6cfb2 Mon Sep 17 00:00:00 2001 From: Afly Date: Tue, 8 Aug 2023 10:51:17 +0800 Subject: [PATCH 4/4] =?UTF-8?q?=E6=97=A0jira=E4=BB=BB=E5=8A=A1=20fix:=20?= =?UTF-8?q?=E6=8F=90=E5=8D=87=E6=8F=92=E4=BB=B6=E7=89=88=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- plugin.xml | 3 ++- .../fanruan/fs/s3/repository/core/S3ResourceRepository.java | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/plugin.xml b/plugin.xml index 0821aa9..9883cd0 100644 --- a/plugin.xml +++ b/plugin.xml @@ -5,12 +5,13 @@ com.fanruan.fs yes no - 1.3.9 + 1.4.0 10.0~10.0 2023-03-14 richie [2023-06-30]修复默认配置获取错误的问题,过滤有问题的路径。
[2023-03-28]第三方组件升级。
[2023-01-03]优化写文件性能; 修复文件太多显示不全的问题。
diff --git a/src/main/java/com/fanruan/fs/s3/repository/core/S3ResourceRepository.java b/src/main/java/com/fanruan/fs/s3/repository/core/S3ResourceRepository.java index 105cccb..f82d7ad 100644 --- a/src/main/java/com/fanruan/fs/s3/repository/core/S3ResourceRepository.java +++ b/src/main/java/com/fanruan/fs/s3/repository/core/S3ResourceRepository.java @@ -79,7 +79,6 @@ public class S3ResourceRepository extends BaseResourceRepository { if (config.getEndPoint().startsWith(HTTP)) { clientConfiguration.setProtocol(Protocol.HTTP); } - clientConfiguration.setProtocol(Protocol.HTTP); amazonS3ClientBuilder = amazonS3ClientBuilder.withClientConfiguration(clientConfiguration); this.s3 = amazonS3ClientBuilder.build(); this.bucket = config.getBucket();