寫在前面
當我們談下載時,要注意什麼?IO?API?SDK?
一、基本知識
下載的過程就是 複製的過程,三個基本名詞 Source File,Target File,傳輸工具
二、Source File
源文件,Java中常見3種源文件,
- 資源路徑-Classpath
- 文件系統 - File System
- 磁盤目錄
2.1、資源路徑
常見場景很多,包括各種模板、手冊(Word,Excel,PDF…),相關靜態文件…
這裏一般通過兩個對象即可操作資源文件,可參考這裏,
獲取 輸出、輸入流,即可完成下載
2.2、文件系統
這裏的場景是基於一個文件服務,目前很多的文件服務的選擇
fastDfs、HDFS、GlusterFS、各種雲盤、各種雲的OSS對象存儲、甚至某個超鏈接…等等都可定義爲文件系統的存儲方式
文件系統的文件操作方法是基於 API,或者 超鏈接方式,即可
這裏有可用的 SDK 或者 相關工具類封裝…完成下載
類似如下,apache common
public static void downloadWithApacheCommons(String url, String localFilename) {
int CONNECT_TIMEOUT = 10000;
int READ_TIMEOUT = 10000;
try {
FileUtils.copyURLToFile(new URL(url), new File(localFilename), CONNECT_TIMEOUT, READ_TIMEOUT);
} catch (IOException e) {
e.printStackTrace();
}
}
2.3、磁盤目錄
這裏需要注意,開發環境,測試環境。以及生產環境因系統不同,文件分割符會有所不同
is = new FileInputStream(filePath + "\\" + path.getFileName()); // windows
is = new FileInputStream(filePath + "/" + path.getFileName()); // linux 目錄分隔符
JDK 中 File.separator 可自動識別系統分隔符,因此上述可替換爲
is = new FileInputStream(filePath + File.separator + path.getFileName());
還要注意 ,Java 項目 和 Springboot 項目測試中的差別,即springboot 項目中的 所獲取Path路徑是相對路徑,會把磁盤某文件真實路徑,映射 當前項目下,導致無法獲取真實文件路徑,獲取輸入流失敗,可參考上述,拼接文件的完整路徑,獲取輸入流
三、Target File
這裏是指期望下載文件到某位置,一般通過瀏覽器方式下載(通過輸出流寫到瀏覽器默認下載目錄)
四、傳輸工具
這裏是指 IO 流的 讀寫方式,包括 字符流、字節流
示例(指向磁盤目錄下載)
這裏完成了 指向目標目錄,過濾文件,下載
// 接口定義
@GetMapping("/manual")
public void manualDownload(HttpServletResponse response) {
InputStream is = null;
ServletOutputStream os = null;
String filePath = configService.findDefaultFilePath();
if (filePath == null) {
throw new CustomeException("文件地址爲空");
}
List<Path> results = new LinkedList<Path>();
try {
Files.walkFileTree(Paths.get(filePath), new FindJavaVisitor(results));
if (results.size() != 1) {
throw new CustomeException("文件異常" + results.size());
}
Path path = results.get(0);
is = new FileInputStream(filePath + File.separator + path.getFileName());
response.addHeader("charset", "utf-8");
String encodeName = URLEncoder.encode(path.getFileName().toString(), StandardCharsets.UTF_8.toString());
response.setHeader("Content-Disposition", "attachment; filename=\"" + encodeName + "\"; filename*=utf-8''" + encodeName);
// copy (輸入流,輸出流)
os = response.getOutputStream();
IOUtils.copy(is, os);
response.flushBuffer();
} catch (Exception e) {
throw new CustomeException("文件異常");
} finally {
try {
if (os != null) {
os.close();
}
if (is != null) {
is.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
// 文件過濾
private static class FindJavaVisitor extends SimpleFileVisitor<Path> {
private List<Path> result;
public FindJavaVisitor(List<Path> result) {
this.result = result;
}
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
if (file.toString().endsWith(".docx")) {
result.add(file.getFileName());
}
return FileVisitResult.CONTINUE;
}
}