哲学家
怕什么真理无穷,进一寸有进一寸的欢喜
SpringMVC 下载文本实现边转码边下载

方案一: PrintWriter + CharacterEncoding

SpringMVC 框架的接口中 Response 有 ServletOutputStreamPrintWriter 两种输出,还有一个 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());


}

补充:

  • 使用 Nginx 可以不通过接口前端直接下载,后续可以尝试采用此方法。

Last modified on 2020-03-04