【问题解决】Java下载远程服务器资源到本地,本地提供下载服务,解决中文乱码问题

Java下载远程服务器资源到本地,本地提供下载服务

1.通过远程访问远程URL获取服务资源

/**
     * 从指定URL下载文件并保存到指定目录
     * @param filePath 文件将要保存的目录
     * @param method 请求方法,包括POST和GET
     * @param name 文件名
     * @param url 请求的路径
     * @return
     */
public static File saveUrlAsFile(String url,String filePath,String method,String name) throws Exception{
    String fileName = name;     //为下载的文件命名
    //创建不同的文件夹目录
    File file=new File(filePath);
    //判断文件夹是否存在
    if (!file.exists())
    {
        //如果文件夹不存在,则创建新的的文件夹
        file.mkdirs();
    }
    FileOutputStream fileOut = null;
    HttpURLConnection conn = null;
    InputStream inputStream = null;
    // 建立链接
    URL httpUrl=new URL(url);
    conn=(HttpURLConnection) httpUrl.openConnection();
    //以Post方式提交表单,默认get方式
    conn.setRequestMethod(method);
    conn.setDoInput(true);
    conn.setDoOutput(true);
    // post方式不能使用缓存
    conn.setUseCaches(false);
    //连接指定的资源
    conn.connect();
    //获取网络输入流
    inputStream=conn.getInputStream();
    BufferedInputStream bis = new BufferedInputStream(inputStream);
    //判断文件的保存路径后面是否以/结尾
    if (!filePath.endsWith("/")) {

        filePath += "/";

    }
    //写入到文件(注意文件保存路径的后面一定要加上文件的名称)
    fileOut = new FileOutputStream(filePath+fileName);
    BufferedOutputStream bos = new BufferedOutputStream(fileOut);

    byte[] buf = new byte[4096];
    int length = bis.read(buf);
    //保存文件
    while(length != -1)
    {
        bos.write(buf, 0, length);
        length = bis.read(buf);
    }
    bos.close();
    bis.close();
    conn.disconnect();
    return file;
}

如此一来远程的服务资源就被成功保存到本地了

2.后台读取本地下载的资源,提供用户下载功能

  • 首先去到之前定义的filePath路径中
    • 不存在:抛出异常
    • 存在:走下载
    • 下载完成后:finally——>循环递归 清除本地资源,释放空间(因为文件File类)
    // 局部代码块
	InputStream inputStream;
    OutputStream outputStream;
    File file1 = new File(filePath);
    try {
        if (file1.exists()){
            response.setContentType(contentType+";charset=utf-8");
            String fileNameURL = URLEncoder.encode(fileName,"UTF-8");
            response.setHeader("Content-disposition", "attachment;filename="+fileNameURL+";"+"filename*=utf-8''"+fileNameURL);

            inputStream = new FileInputStream(filePath+"/"+courseName + "/" + fileName);
            outputStream = new BufferedOutputStream(response.getOutputStream());
            byte[] bytes = new byte[1024];
            int len;
            while ((len = inputStream.read(bytes)) != -1){
                response.getOutputStream().write(bytes,0,len);
            }
            outputStream.flush();
            outputStream.close();
            inputStream.close();
        }
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } finally {
        //删除本地文件
        deleteFile(file1);
    }

3.删除本地文件

public static void deleteFile(File file){
    //判断文件不为null或文件目录存在
    if (file == null || !file.exists()){
        System.out.println("文件删除失败,请检查文件路径是否正确");
        return;
    }
    //取得这个目录下的所有子文件对象
    File[] files = file.listFiles();
    //遍历该目录下的文件对象
    for (File f: files){
        //打印文件名
        String name = file.getName();
        //判断子目录是否存在子目录,如果是文件则删除
        if (f.isDirectory()){
            deleteFile(f);
        }else {
            f.delete();
        }
    }
    //删除空文件夹  for循环已经把上一层节点的目录清空。
    file.delete();
}

踩坑总结

在获取服务器资源和后端提供下载的服务的时候都很顺利,但是在下载文件的时候,遇到文件名称带有中文就会出现问题!!

最初版本:

/** 上面代码省略,此处仅显示响应部分 */
response.setContentType(contentType+";charset=UTF-8");
response.setHeader("Content-disposition", "attachment;filename="+fileName);
/** 下面代码相同,省略 */

这种做法可以正常下载:名字只包含数字和英文的文件,但是在遇到包含中文的文件,中文部分就会不显示并且连后缀都没有咯。

示例:本地要下载的文件名称(java基础语法.doc),点击下载后提示保存的文件名称(java),后缀也就都没有了。虽然说你可以手动把后缀给加上去后正常打开,但是体验感极差,况且,作为一个普通用户,并不知道你原文件的格式具体是什么。。

第二代版本:

尝试了网上的各种也都不行

//例如1
finalFileName = new String(fileName.getBytes("UTF-8"), "ISO-8859-1");
response.setHeader("Content-disposition", "attachment;filename="+finalFileName);

//例如2
response.setHeader("Content-disposition", "attachment;filename="+URLEncoder.encode(fileName,"UTF8"));

第一次完全没反应= =,带中文名称的文件下载下来和初代版本一样,捞不谈

第二种可以正常下载文件了,并且可以正常打开。但是下载过后文件名称出现乱码

#具体就是这种感觉
java基础语法.doc        ——————————》java%32%512E%152113%12.doc   (大概就是这种感觉)

虽说不影响使用,但是看起来及其难受

最终版本:

String fileNameURL = URLEncoder.encode(fileName,"UTF-8");
response.setHeader("Content-disposition", "attachment;filename="+fileNameURL+";"+"filename*=utf-8''"+fileNameURL);

有效解决下载文件中文编码乱码问题。心累啊~

常用文件后缀及其编码枚举类(FileSuffix)

package com.jeesite.modules.study.entity.enums;

public enum FileSuffix {
    DOC("doc", "application/msword"),
    DOCX("docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document"),
    XLS("xls", "text/xml"),
    XLSX("xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"),
    PPT("ppt", "application/vnd.ms-powerpoint"),
    PPTX("pptx", "application/vnd.openxmlformats-officedocument.presentationml.presentation"),
    PDF("pdf", "application/pdf"),
    WPS("wps", "application/vnd.ms-works"),
    TXT("txt", "text/plain"),
    MP4("mp4", "video/mp4");

    FileSuffix(String suffix, String contentType) {
        this.suffix = suffix;
        this.contentType = contentType;
    }

    private String suffix;

    private String contentType;

    public String getSuffix() {
        return suffix;
    }

    public void setSuffix(String suffix) {
        this.suffix = suffix;
    }

    public String getContentType() {
        return contentType;
    }

    public void setContentType(String contentType) {
        this.contentType = contentType;
    }

    public static String getContentType(String suffix) {
        FileSuffix[] values = FileSuffix.values();
        for (FileSuffix item : values) {
            if (item.getSuffix().equals(suffix)) {
                return item.getContentType();
            }
        }
        return null;
    }
}

完整代码

public void downloadOneFile(String id, HttpServletResponse response) throws Exception {
    //指定下载到服务器的地址
    String filePath = "/usr/local/files" + UUID.randomUUID() + "/";
    //查询id对应的文件名称,地址,URL
    Map<String, Object> file = stStudentService.downloadOneFile(id);
    if (file != null) {
        String fileName = file.get("fileName").toString();
        if (file.get("fileName") != null && fileName.length() > 80) {
            fileName = fileName.substring(0, 80);
        }
        String courseName = file.get("courseName").toString();
        if (file.get("courseName") != null && courseName.length() > 80) {
            courseName = courseName.substring(0, 80);
        }
        //文件路径
        String fileUrl = file.get("fileUrl").toString();
        String[] split = fileName.split("\\.");
        //文件后缀
        String suffix = split[split.length - 1];
        //自定义枚举类,匹配 后缀名所对应的contentType
        String contentType = FileSuffix.getContentType(suffix);
		//获取并下载服务器资源到本地
        DownloadFiles.saveUrlAsFile(fileUrl, filePath + "/" + courseName, "GET", fileName);

        //提供本地下载服务
        InputStream inputStream;
        OutputStream outputStream;
        File file1 = new File(filePath);
        try {
            if (file1.exists()){
                response.setContentType(contentType+";charset=utf-8");
                String fileNameURL = URLEncoder.encode(fileName,"UTF-8");
                response.setHeader("Content-disposition", "attachment;filename="+fileNameURL+";"+"filename*=utf-8''"+fileNameURL);

                inputStream = new FileInputStream(filePath+"/"+courseName + "/" + fileName);
                outputStream = new BufferedOutputStream(response.getOutputStream());
                byte[] bytes = new byte[1024];
                int len;
                while ((len = inputStream.read(bytes)) != -1){
                    response.getOutputStream().write(bytes,0,len);
                }
                outputStream.flush();
                outputStream.close();
                inputStream.close();
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } finally {
            //删除本地文件,释放资源
            deleteFile(file1);
        }
    }
}

你可能感兴趣的:(java,问题解决,java)