SpringMVC 下载文本实现边转码边下载
边转码边下载
下载通常都会遇到这种情况,代码里通常保存为 utf-8 格式,但是用户想要 gbk 格式,实现思路如下:
方案一: PrintWriter + CharacterEncoding
SpringMVC 框架的接口中 Response 有 ServletOutputStream
和 PrintWriter
两种输出,还有一个 setCharacterEncoding
方法。
OutPutStream 视为写入二进制数据,容器不对二进制数据进行编码,即 setCharacterEncoding
无效。所以先采用 PrintWriter
搭配 setCharacterEncoding
方法。
@GetMapping("/downloadFile1")
public void downloadFile1(HttpServletResponse response) throws IOException{
//读取本地文件
File file = new File(LOCAL_FILE_PATH);
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8"));
//设置下载
response.setHeader("Content-Disposition", "attachment;filename=file.csv");
response.setContentType("application/octet-stream");
response.setCharacterEncoding("GB2312");
//传输
BufferedWriter bufferedWriter = new BufferedWriter(response.getWriter());
String line;
while ((line = bufferedReader.readLine()) != null) {
bufferedWriter.write(line + "\r\n");
bufferedWriter.flush();
}
bufferedReader.close();
bufferedWriter.close();
}
无用,没有仔细研究,应该 setCharacterEncoding
只是告诉浏览器是什么编码,没有解码功能。
方案二:ServletOutputStream + OutputStreamWriter
将 response.getOutputStream()
获取到的流用 OutputStreamWriter
包装。结果可行。
@GetMapping("/downloadFile2")
public void downloadFile2(HttpServletResponse response) throws IOException{
//读取本地文件
File file = new File(LOCAL_FILE_PATH);
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8"));
//设置下载
response.setHeader("Content-Disposition", "attachment;filename=file.csv");
response.setContentType("application/octet-stream");
//传输
OutputStreamWriter writerStream = new OutputStreamWriter(response.getOutputStream(),"GBK");
String line;
while ((line = bufferedReader.readLine()) != null) {
writerStream.write(line + "\r\n");
writerStream.flush();
}
bufferedReader.close();
writerStream.close();
}
方案三:ServletOutputStream + getBytes
在按行写入字符串时,使用 getBytes
方法将字符串转换为想要输出的编码格式。结果可行。
@GetMapping("/downloadFile3")
public void downloadFile3(HttpServletResponse response) throws IOException{
//读取本地文件
File file = new File(LOCAL_FILE_PATH);
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8"));
//设置下载
response.setHeader("Content-Disposition", "attachment;filename=file.csv");
response.setContentType("application/octet-stream");
//传输
OutputStream outputStream = response.getOutputStream();
String line;
while ((line = bufferedReader.readLine()) != null) {
outputStream.write((line + "\r\n").getBytes("GB2312"));
outputStream.flush();
}
bufferedReader.close();
outputStream.close();
}
无需转换的写法
若不需要转码的话,就很简短了,用字节流就行了。
@GetMapping("/downloadFile4")
public void downloadFile4(HttpServletResponse response) throws IOException{
//读取本地文件
File file = new File(LOCAL_FILE_PATH);
FileInputStream fis = new FileInputStream(file);
//设置下载
response.setHeader("Content-Disposition", "attachment;filename=file.csv");
response.setContentType("application/octet-stream");
//传输
OutputStream os = response.getOutputStream();
byte[] buffer = new byte[4096];
int b = -1;
while ((b = fis.read(buffer)) != -1) {
os.write(buffer, 0, b);
}
fis.close();
os.close();
}
简写的话可以用第三方包。
import org.springframework.util.FileCopyUtils;
@GetMapping("/downloadFile5")
public void downloadFile5(HttpServletResponse response) throws IOException{
//读取本地文件
File file = new File(LOCAL_FILE_PATH);
InputStream inputStream= new BufferedInputStream(new FileInputStream(file));
//设置下载
response.setHeader("Content-Disposition", "attachment;filename=file.csv");
response.setContentType("application/octet-stream");
//传输
FileCopyUtils.copy(inputStream, response.getOutputStream());
}
多文件打包下载
当需要下载多个文件时,可以将其打包成一个文件,然后下载。Java 自带的 ZipOutputStream
可以实现。
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
@Override
public void download(OutputStream outputStream) throws IOException {
// Create the ZIP file
ZipOutputStream zipOut = new ZipOutputStream(outputStream);
// image demo
Map<String, String> imageMap = new HashMap<>;
//add file to zip
ZipEntry zipEntry;
for (String imageName : imageMap.keySet()) {
// http://192.168.0.102:13080/pcg/files/image/64280347-afa8-4057-8941-ccbaeebf3c4b
File fileToZip = new File(StaticProperty.IMAGE_PATH, imageMap.get(imageName));
try (FileInputStream fis = new FileInputStream(fileToZip)) {
zipEntry = new ZipEntry(imageName);
zipOut.putNextEntry(zipEntry);
byte[] bytes = new byte[1024];
int length;
while((length = fis.read(bytes)) >= 0) {
zipOut.write(bytes, 0, length);
}
}catch (FileNotFoundException fnfe){
LOG.warn("file {} not found", imageMap.get(imageName));
}
zipOut.closeEntry();
}
zipOut.flush();
zipOut.close();
补充:
- 使用 Nginx 可以不通过接口前端直接下载,后续可以尝试采用此方法。
Last modified on 2020-03-04