From 11d581aaf030282b4c32a47cb83094b6b77d9657 Mon Sep 17 00:00:00 2001 From: "ran.shang" <> Date: Wed, 27 Aug 2025 18:02:40 +0800 Subject: [PATCH] file download range --- .../component/file/service/IFileStorage.java | 1 + .../file/service/impl/FileServiceImpl.java | 30 +------------ .../file/service/storage/AliFileStorage.java | 44 ++++++++++++++++++- .../service/storage/LocalFileStorage.java | 25 +++++++++++ 4 files changed, 71 insertions(+), 29 deletions(-) diff --git a/src/main/java/com/newyetai/component/file/service/IFileStorage.java b/src/main/java/com/newyetai/component/file/service/IFileStorage.java index bf9632c..0bfad2d 100644 --- a/src/main/java/com/newyetai/component/file/service/IFileStorage.java +++ b/src/main/java/com/newyetai/component/file/service/IFileStorage.java @@ -31,4 +31,5 @@ public interface IFileStorage { */ InputStream download(String filePath); + void downloadRange(String filePath, OutputStream outputStream, long start, long length); } diff --git a/src/main/java/com/newyetai/component/file/service/impl/FileServiceImpl.java b/src/main/java/com/newyetai/component/file/service/impl/FileServiceImpl.java index 7481b91..7b0633c 100644 --- a/src/main/java/com/newyetai/component/file/service/impl/FileServiceImpl.java +++ b/src/main/java/com/newyetai/component/file/service/impl/FileServiceImpl.java @@ -43,6 +43,7 @@ import com.newyetai.component.file.service.FileClassService; import com.newyetai.component.file.service.FileRecordService; import com.newyetai.component.file.service.FileService; import com.newyetai.component.file.service.IFileStorage; +import com.newyetai.component.file.service.storage.AliFileStorage; import com.newyetai.component.file.util.FileUtils; import cn.hutool.core.date.DateUtil; @@ -203,7 +204,7 @@ public class FileServiceImpl implements FileService { response.setHeader("Content-Length", String.valueOf(contentLength)); // 下载指定范围的内容 - downloadRange(fileRecord.getFilePath(), response.getOutputStream(), start, contentLength); + fileStorage.downloadRange(fileRecord.getFilePath(), response.getOutputStream(), start, contentLength); } catch (NumberFormatException e) { log.warn("无效的Range请求: {}", rangeHeader); @@ -213,33 +214,6 @@ public class FileServiceImpl implements FileService { } } - /** - * 下载文件的指定范围 - */ - private void downloadRange(String filePath, OutputStream outputStream, long start, long length) throws IOException { - try (InputStream inputStream = fileStorage.download(filePath)) { - // 跳过开始位置之前的字节 - long skipped = inputStream.skip(start); - if (skipped != start) { - log.warn("跳过字节数不匹配,期望: {}, 实际: {}", start, skipped); - } - - // 读取指定长度的数据 - byte[] buffer = new byte[8192]; - long remaining = length; - int bytesRead; - - while (remaining > 0 && (bytesRead = inputStream.read(buffer, 0, (int) Math.min(buffer.length, remaining))) != -1) { - outputStream.write(buffer, 0, bytesRead); - remaining -= bytesRead; - } - - outputStream.flush(); - } - } - - - @Override public void checkFile(MultipartFile file, String code) { Assert.notBlank(code, "未指定文件配置"); diff --git a/src/main/java/com/newyetai/component/file/service/storage/AliFileStorage.java b/src/main/java/com/newyetai/component/file/service/storage/AliFileStorage.java index b0b9956..9f6aad8 100644 --- a/src/main/java/com/newyetai/component/file/service/storage/AliFileStorage.java +++ b/src/main/java/com/newyetai/component/file/service/storage/AliFileStorage.java @@ -13,9 +13,9 @@ import com.aliyun.oss.ClientException; import com.aliyun.oss.OSS; import com.aliyun.oss.OSSClientBuilder; import com.aliyun.oss.OSSException; +import com.aliyun.oss.model.GetObjectRequest; import com.aliyun.oss.model.OSSObject; import com.newyetai.common.constant.CommonConstants; -import com.newyetai.common.exception.BusinessException; import com.newyetai.common.exception.DevopsException; import com.newyetai.common.exception.util.Assert; import com.newyetai.common.util.EnvironmentUtils; @@ -120,4 +120,46 @@ public class AliFileStorage implements IFileStorage { } } + @Override + public void downloadRange(String filePath, OutputStream outputStream, long start, long length) { + try { + // 创建GetObjectRequest并设置Range + GetObjectRequest getObjectRequest = new GetObjectRequest(bucketName, dealPath(filePath)); + getObjectRequest.setRange(start, start + length - 1); + + // 调用ossClient.getObject返回一个OSSObject实例 + OSSObject ossObject = ossClient.getObject(getObjectRequest); + // 调用ossObject.getObjectContent获取文件输入流 + try (InputStream inputStream = ossObject.getObjectContent();) { + // 使用更大的缓冲区提高性能 + byte[] buffer = new byte[64 * 1024]; // 64KB缓冲区 + long remaining = length; + int bytesRead; + + while (remaining > 0 && (bytesRead = inputStream.read(buffer, 0, (int) Math.min(buffer.length, remaining))) != -1) { + outputStream.write(buffer, 0, bytesRead); + remaining -= bytesRead; + } + + outputStream.flush(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } catch (OSSException oe) { + log.info("Caught an OSSException, which means your request made it to OSS, " + + "but was rejected with an error response for some reason."); + log.info("Error Message:" + oe.getErrorMessage()); + log.info("Error Code:" + oe.getErrorCode()); + log.info("Request ID:" + oe.getRequestId()); + log.info("Host ID:" + oe.getHostId()); + throw new DevopsException("oss请求异常" + oe.getMessage()); + } catch (ClientException ce) { + log.info("Caught an ClientException, which means the client encountered " + + "a serious internal problem while trying to communicate with OSS, " + + "such as not being able to access the network."); + log.info("Error Message:" + ce.getMessage()); + throw new DevopsException("oss客户端异常" + ce.getMessage()); + } + } + } diff --git a/src/main/java/com/newyetai/component/file/service/storage/LocalFileStorage.java b/src/main/java/com/newyetai/component/file/service/storage/LocalFileStorage.java index 11ce8ac..bea95b0 100644 --- a/src/main/java/com/newyetai/component/file/service/storage/LocalFileStorage.java +++ b/src/main/java/com/newyetai/component/file/service/storage/LocalFileStorage.java @@ -55,4 +55,29 @@ public class LocalFileStorage implements IFileStorage { } } + @Override + public void downloadRange(String filePath, OutputStream outputStream, long start, long length) { + try (InputStream inputStream = this.download(filePath)) { + // 跳过开始位置之前的字节 + long skipped = inputStream.skip(start); + if (skipped != start) { + log.warn("跳过字节数不匹配,期望: {}, 实际: {}", start, skipped); + } + + // 使用更大的缓冲区 + byte[] buffer = new byte[64 * 1024]; // 64KB缓冲区 + long remaining = length; + int bytesRead; + + while (remaining > 0 && (bytesRead = inputStream.read(buffer, 0, (int) Math.min(buffer.length, remaining))) != -1) { + outputStream.write(buffer, 0, bytesRead); + remaining -= bytesRead; + } + + outputStream.flush(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + }