file download range

This commit is contained in:
ran.shang
2025-08-27 18:02:40 +08:00
parent 59ef112929
commit 11d581aaf0
4 changed files with 71 additions and 29 deletions

View File

@@ -31,4 +31,5 @@ public interface IFileStorage {
*/
InputStream download(String filePath);
void downloadRange(String filePath, OutputStream outputStream, long start, long length);
}

View File

@@ -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, "未指定文件配置");

View File

@@ -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());
}
}
}

View File

@@ -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);
}
}
}