file download range
This commit is contained in:
@@ -31,4 +31,5 @@ public interface IFileStorage {
|
|||||||
*/
|
*/
|
||||||
InputStream download(String filePath);
|
InputStream download(String filePath);
|
||||||
|
|
||||||
|
void downloadRange(String filePath, OutputStream outputStream, long start, long length);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ import com.newyetai.component.file.service.FileClassService;
|
|||||||
import com.newyetai.component.file.service.FileRecordService;
|
import com.newyetai.component.file.service.FileRecordService;
|
||||||
import com.newyetai.component.file.service.FileService;
|
import com.newyetai.component.file.service.FileService;
|
||||||
import com.newyetai.component.file.service.IFileStorage;
|
import com.newyetai.component.file.service.IFileStorage;
|
||||||
|
import com.newyetai.component.file.service.storage.AliFileStorage;
|
||||||
import com.newyetai.component.file.util.FileUtils;
|
import com.newyetai.component.file.util.FileUtils;
|
||||||
|
|
||||||
import cn.hutool.core.date.DateUtil;
|
import cn.hutool.core.date.DateUtil;
|
||||||
@@ -203,7 +204,7 @@ public class FileServiceImpl implements FileService {
|
|||||||
response.setHeader("Content-Length", String.valueOf(contentLength));
|
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) {
|
} catch (NumberFormatException e) {
|
||||||
log.warn("无效的Range请求: {}", rangeHeader);
|
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
|
@Override
|
||||||
public void checkFile(MultipartFile file, String code) {
|
public void checkFile(MultipartFile file, String code) {
|
||||||
Assert.notBlank(code, "未指定文件配置");
|
Assert.notBlank(code, "未指定文件配置");
|
||||||
|
|||||||
@@ -13,9 +13,9 @@ import com.aliyun.oss.ClientException;
|
|||||||
import com.aliyun.oss.OSS;
|
import com.aliyun.oss.OSS;
|
||||||
import com.aliyun.oss.OSSClientBuilder;
|
import com.aliyun.oss.OSSClientBuilder;
|
||||||
import com.aliyun.oss.OSSException;
|
import com.aliyun.oss.OSSException;
|
||||||
|
import com.aliyun.oss.model.GetObjectRequest;
|
||||||
import com.aliyun.oss.model.OSSObject;
|
import com.aliyun.oss.model.OSSObject;
|
||||||
import com.newyetai.common.constant.CommonConstants;
|
import com.newyetai.common.constant.CommonConstants;
|
||||||
import com.newyetai.common.exception.BusinessException;
|
|
||||||
import com.newyetai.common.exception.DevopsException;
|
import com.newyetai.common.exception.DevopsException;
|
||||||
import com.newyetai.common.exception.util.Assert;
|
import com.newyetai.common.exception.util.Assert;
|
||||||
import com.newyetai.common.util.EnvironmentUtils;
|
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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user