response.outputStream乱码且输出不正确,求大神教一下


//批量下载文件并打包
    public static void downLoadZipAllFile(HttpServletRequest request, HttpServletResponse response, List<Map<String,String>> maps) {
        OutputStream outp = null;
        ZipOutputStream zos = null;
        BufferedInputStream bis = null;
        String downloadZipDir = "D:/ftpHome/downloadZip";
        try {
            outp = response.getOutputStream();
            response.setCharacterEncoding("UTF-8");
            response.setContentType("text/html; charset=UTF-8"); //设置编码字符
            response.setContentType("application/octet-stream"); //设置内容类型为下载类型
//            response.setContentType("application/zip");// 定义输出类型
            String timeSuffix = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
            String zipFilePath = downloadZipDir + "/" + timeSuffix + "_DataFile.zip";
            String filedisplay = zipFilePath;
            if (filedisplay.indexOf("/") >= 0) {
                filedisplay = filedisplay.substring(filedisplay.lastIndexOf("/") + 1);
            } else if (filedisplay.indexOf("\\") >= 0) {
                filedisplay = filedisplay.substring(filedisplay.lastIndexOf("\\") + 1);
            }
            String agent = (String) request.getHeader("USER-AGENT");
            // firefox
            if (agent != null && agent.indexOf("MSIE") == -1) {
                String enableFileName = "=?UTF-8?B?"
                        + (new String(Base64.getBase64(filedisplay))) + "?=";
                response.setHeader("Content-Disposition",
                        "attachment; filename=" + enableFileName);
            } else {
                filedisplay = URLEncoder.encode(filedisplay, "utf-8");
                response.addHeader("Content-Disposition",
                        "attachment;filename=" + filedisplay);
            }
            try {
//                File zip = new File(zipFilePath);
//                if (!zip.exists()) {
//                    zip.createNewFile();
//                }
                zos = new ZipOutputStream(new FileOutputStream(zipFilePath));
                for (Map<String, String> map : maps) {
                    String filePath = map.get("filePath");
                    String filename = map.get("fileName");
                    File file = new File(filePath);
                    if (file.exists()) {
                        zos.putNextEntry(new ZipEntry(filename));
                        zos.setEncoding("GBK");
                        bis = new BufferedInputStream(new FileInputStream(file));
                        byte[] b = new byte[1024 * 64];
                        int i = 0;
                        while ((i = bis.read(b)) > 0) {
                            zos.write(b, 0, i);
                        }
                        zos.closeEntry();
                        bis.close();
                        String isDelete = request.getParameter("isDelete");
                        if ("1".equals(isDelete)) {
                            file.delete();
                        }
                    }
//                    else {
//                        outp.write("文件不存在!".getBytes("GBK"));
//                    }
                }
                zos.close();
                InputStream ins = new FileInputStream(zipFilePath);
                BufferedInputStream bins = new BufferedInputStream(ins);// 放到缓冲流里面
                BufferedOutputStream bouts = new BufferedOutputStream(outp);
                int bytesRead = 0;
                byte[] buffer = new byte[8192];
                // 开始向网络传输文件流
                while ((bytesRead = bins.read(buffer, 0, 8192)) != -1) {
                    bouts.write(buffer, 0, bytesRead);
                }
                bouts.flush();// 这里一定要调用flush()方法
                ins.close();
                bins.close();
                outp.close();
                bouts.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
//            finally {
//                if (bis != null) {
//                    bis.close();
//                    bis = null;
//                }
////                if (zos != null) {
////                    zos.close();
////                    zos = null;
////                }
////                if (outp != null) {
////                    outp.close();
////                    outp = null;
////                }
//            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

目前的效果是能在文件夹中看到压缩好的包,但是把这个zip包通过流的方式发送到浏览器,也就是利用response.getOutputStream,为啥弹出来的不是zip包,而是其中一个文件,并且文件中乱码,求各位大神教教呀!

img

img

img

谷歌浏览器乱码情况如下:

img

参考GPT:可能是因为你在设置response的ContentType时,同时设置了"text/html; charset=UTF-8"和"application/octet-stream"两种类型,导致输出的内容既不是html文本,也不是二进制流类型,而是一些混合的内容,从而导致浏览器无法正确处理文件类型。

你可以尝试修改代码,只保留设置"application/octet-stream"的内容类型,并删除设置"text/html; charset=UTF-8"的代码行。另外,也可以将写入Zip文件的编码方式设置为UTF-8,这样可以确保文件内容的正确性。下面是修改后的代码片段:

outp = response.getOutputStream();
response.setContentType("application/octet-stream");
String timeSuffix = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
String zipFilePath = downloadZipDir + "/" + timeSuffix + "_DataFile.zip";
String filedisplay = zipFilePath;
if (filedisplay.indexOf("/") >= 0) {
    filedisplay = filedisplay.substring(filedisplay.lastIndexOf("/") + 1);
} else if (filedisplay.indexOf("\\") >= 0) {
    filedisplay = filedisplay.substring(filedisplay.lastIndexOf("\\") + 1);
}
String agent = (String) request.getHeader("USER-AGENT");
if (agent != null && agent.indexOf("MSIE") == -1) {
    String enableFileName = "=?UTF-8?B?" + (new String(Base64.getBase64(filedisplay))) + "?=";
    response.setHeader("Content-Disposition", "attachment; filename=" + enableFileName);
} else {
    filedisplay = URLEncoder.encode(filedisplay, "utf-8");
    response.addHeader("Content-Disposition", "attachment;filename=" + filedisplay);
}
try {
    zos = new ZipOutputStream(new FileOutputStream(zipFilePath), Charset.forName("UTF-8"));
    for (Map<String, String> map : maps) {
        String filePath = map.get("filePath");
        String filename = map.get("fileName");
        File file = new File(filePath);
        if (file.exists()) {
            zos.putNextEntry(new ZipEntry(filename));
            bis = new BufferedInputStream(new FileInputStream(file));
            byte[] b = new byte[1024 * 64];
            int i = 0;
            while ((i = bis.read(b)) > 0) {
                zos.write(b, 0, i);
            }
            zos.closeEntry();
            bis.close();
            String isDelete = request.getParameter("isDelete");
            if ("1".equals(isDelete)) {
                file.delete();
            }
        }
    }
    zos.close();
    InputStream ins = new FileInputStream(zipFilePath);
    BufferedInputStream bins = new BufferedInputStream(ins);
    BufferedOutputStream bouts = new BufferedOutputStream(outp);
    int bytesRead = 0;
    byte[] buffer = new byte[8192];
    while ((bytesRead = bins.read(buffer, 0, 8192)) != -1) {
        bouts.write(buffer, 0, bytesRead);
    }
    bouts.flush();
    ins.close();
    bins.close();
    outp.close();
    bouts.close();
} catch (Exception e) {
    e.printStackTrace();
}


该回答引用GPTᴼᴾᴱᴺᴬᴵ以及自己的分析思考,具体如下:

从你提供的代码中,我看到你在使用ZipOutputStream输出文件时设置了编码为GBK,而在设置Content-Type为application/octet-stream之后,却没有设置字符编码,这可能导致乱码的问题。可以尝试在设置Content-Type后,再设置一个Content-Disposition的header来指定文件名,同时指定编码为UTF-8,具体的代码如下例子。

例如:

response.setContentType("application/octet-stream"); //设置内容类型为下载类型
String filename = "example.zip";
response.setHeader("Content-Disposition", "attachment;filename*=utf-8''" + URLEncoder.encode(filename, "UTF-8"));

其中,filename*=utf-8''是为了让浏览器能正确解析文件名中的特殊字符。同时,也可以尝试将ZipOutputStream的编码设置为UTF-8。

如果以上回答对您有所帮助,望采纳~谢谢

关于response.outputStream乱码的问题,我看到你上设置的是charset=UTF-8,但是压缩包的格式设置的是 zos.setEncoding("GBK");这里检查是不是这里的问题

以下答案由GPT-3.5大模型与博主波罗歌共同编写:
首先,代码中有一个地方需要修改,就是设置编码字符的地方,应该改成:

response.setCharacterEncoding("UTF-8");
response.setHeader("Content-Disposition", "attachment; filename=\""
        + new String(filedisplay.getBytes("UTF-8"), "ISO8859-1") + "\"");

原来的代码是设置了两次response.setContentType,第二次设置的是下载类型,但是这样会覆盖掉第一次设置的编码类型,所以应该删除掉第二次设置。另外,对于中文文件名,应该使用ISO8859-1编码,否则下载时中文文件名可能会出现乱码。

其次,关于文件乱码的问题,可能是因为在压缩文件时使用了zos.setEncoding("GBK")指定了编码方式,但是在下载文件时并没有指定编码方式,所以可以将zos.setEncoding("GBK")这一行代码删除试试。

最后,关于只下载其中一个文件的问题,可以将最后几行代码的while循环改成:

byte[] buffer = new byte[8192];
int len;
while ((len = ins.read(buffer)) > 0) {
    outp.write(buffer, 0, len);
}

修改完之后,整个方法的代码应该是这样的:

public static void downLoadZipAllFile(HttpServletRequest request, HttpServletResponse response, List<Map<String,String>> maps) {
    OutputStream outp = null;
    ZipOutputStream zos = null;
    BufferedInputStream bis = null;
    String downloadZipDir = "D:/ftpHome/downloadZip";
    try {
        outp = response.getOutputStream();
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/octet-stream"); //设置内容类型为下载类型
        String timeSuffix = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
        String zipFilePath = downloadZipDir + "/" + timeSuffix + "_DataFile.zip";
        String filedisplay = zipFilePath;
        if (filedisplay.indexOf("/") >= 0) {
            filedisplay = filedisplay.substring(filedisplay.lastIndexOf("/") + 1);
        } else if (filedisplay.indexOf("\\") >= 0) {
            filedisplay = filedisplay.substring(filedisplay.lastIndexOf("\\") + 1);
        }
        response.setHeader("Content-Disposition", "attachment; filename=\""
                + new String(filedisplay.getBytes("UTF-8"), "ISO8859-1") + "\"");
        try {
            zos = new ZipOutputStream(new FileOutputStream(zipFilePath));
            for (Map<String, String> map : maps) {
                String filePath = map.get("filePath");
                String filename = map.get("fileName");
                File file = new File(filePath);
                if (file.exists()) {
                    zos.putNextEntry(new ZipEntry(filename));
                    bis = new BufferedInputStream(new FileInputStream(file));
                    byte[] b = new byte[1024 * 64];
                    int i = 0;
                    while ((i = bis.read(b)) > 0) {
                        zos.write(b, 0, i);
                    }
                    zos.closeEntry();
                    bis.close();
                    String isDelete = request.getParameter("isDelete");
                    if ("1".equals(isDelete)) {
                        file.delete();
                    }
                }
            }
            zos.close();
            InputStream ins = new FileInputStream(zipFilePath);
            BufferedInputStream bins = new BufferedInputStream(ins);
            byte[] buffer = new byte[8192];
            int len;
            while ((len = ins.read(buffer)) > 0) {
                outp.write(buffer, 0, len);
            }
            outp.flush();
        } catch (Exception e) {
            e.printStackTrace();
        }
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        if (bis != null) {
            try {
                bis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        if (outp != null) {
            try {
                outp.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

如果我的回答解决了您的问题,请采纳!


response.setHeader("Content-Disposition", "attachment;filename=" + filename); // 告诉浏览器以附件的形式下载文件,并指定文件名称

只要以上一个响应头就够了,因为本身就是要二进制流下载文件,所以不需要在响应头中设置字符集

该回答引用于gpt与OKX安生共同编写:
  • 该回答引用于gpt与OKX安生共同编写:

根据您提供的代码和截图,您正在使用 Java 编写一个 Web 应用程序,下载并打包文件,并将其作为 ZIP 文件发送到浏览器。

我注意到您已经设置了 response.setContentType("application/octet-stream"),这是一种通用的二进制流内容类型,因此它应该可以正确发送 ZIP 文件。但是,在您的屏幕截图中,我们可以看到您在浏览器中看到的似乎是一个具有随机字符的文本文件。这表明您正在尝试将 ZIP 文件作为文本文件发送,而不是正确地设置响应头以指示响应数据是二进制内容。

您可以尝试以下操作来解决这个问题:

  1. 确保您在响应头中正确地设置了“Content-Type”以指示客户端接收到的数据类型是 ZIP 文件。例如,您可以使用以下代码行设置 Content-Type 并将文件名附加到响应头中:
response.setContentType("application/zip");
response.setHeader("Content-Disposition", "attachment;filename=download.zip");
  1. 确保您没有对输出流进行任何编码或其他处理。您可以尝试使用以下代码行将输出流重置为二进制模式:
response.getOutputStream().write(zipBytes);
response.getOutputStream().flush();
response.getOutputStream().close();
  1. 检查您的 ZIP 文件是否正确生成,并且您正在读取正确的文件内容。您可以使用以下命令检查 ZIP 文件内容:
unzip -l download.zip
  • 如有用的话,还请采纳哦~
问题分析:
根据代码分析,可以看出是将多个文件打包成zip文件,然后通过response.getOutputStream()将zip文件发送到浏览器进行下载。但是在实际操作中,下载的文件不是zip文件,而是其中一个文件,并且文件中存在乱码。
问题原因:
1. 设置response的contentType为"text/html; charset=UTF-8",这个contentType不适合下载文件,应该设置为"application/octet-stream"。
2. 在写入zip文件时,设置了zos.setEncoding("GBK"),这个编码方式与response设置的编码方式不一致,导致输出乱码。
3. 在写入zip文件时,没有指定编码方式,应该使用new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(zipFilePath), 1024), Charset.forName("GBK"))指定编码方式。
4. 在写入zip文件时,应该使用try-with-resources语句,确保资源被正确关闭。
5. 在发送zip文件时,应该使用try-with-resources语句,确保资源被正确关闭。
解决方案:
1. 将response的contentType设置为"application/octet-stream"。
2. 删除zos.setEncoding("GBK"),使用new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(zipFilePath), 1024), Charset.forName("GBK"))指定编码方式。
3. 在写入zip文件时,使用try-with-resources语句,确保资源被正确关闭。
4. 在发送zip文件时,使用try-with-resources语句,确保资源被正确关闭。
修改后的代码如下:
//批量下载文件并打包
public static void downLoadZipAllFile(HttpServletRequest request, HttpServletResponse response, List> maps) {
String downloadZipDir = "D:/ftpHome/downloadZip";
try (OutputStream outp = response.getOutputStream();
ZipOutputStream zos = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(zipFilePath), 1024), Charset.forName("GBK"))) {
response.setCharacterEncoding("UTF-8");
response.setContentType("application/octet-stream"); //设置内容类型为下载类型
String timeSuffix = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
String zipFilePath = downloadZipDir + "/" + timeSuffix + "_DataFile.zip";
String filedisplay = zipFilePath;
if (filedisplay.indexOf("/") >= 0) {
filedisplay = filedisplay.substring(filedisplay.lastIndexOf("/") + 1);
} else if (filedisplay.indexOf("\\\\") >= 0) {
filedisplay = filedisplay.substring(filedisplay.lastIndexOf("\\\\") + 1);
}
String agent = (String) request.getHeader("USER-AGENT");
// firefox
if (agent != null && agent.indexOf("MSIE") == -1) {
String enableFileName = "=?UTF-8?B?"
+ (new String(Base64.getBase64(filedisplay))) + "?=";
response.setHeader("Content-Disposition",
"attachment; filename=" + enableFileName);
} else {
filedisplay = URLEncoder.encode(filedisplay, "utf-8");
response.addHeader("Content-Disposition",
"attachment;filename=" + filedisplay);
}
for (Map map : maps) {
String filePath = map.get("filePath");
String filename = map.get("fileName");
File file = new File(filePath);
if (file.exists()) {
zos.putNextEntry(new ZipEntry(filename));
try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file))) {
byte[] b = new byte[1024 * 64];
int i = 0;
while ((i = bis.read(b)) > 0) {
zos.write(b, 0, i);
}
}
zos.closeEntry();
String isDelete = request.getParameter("isDelete");
if ("1".equals(isDelete)) {
file.delete();
}
}
}
zos.close();
try (InputStream ins = new FileInputStream(zipFilePath);
BufferedInputStream bins = new BufferedInputStream(ins);
BufferedOutputStream bouts = new BufferedOutputStream(outp)) {
int bytesRead = 0;
byte[] buffer = new byte[8192];
while ((bytesRead = bins.read(buffer, 0, 8192)) != -1) {
bouts.write(buffer, 0, bytesRead);
}
bouts.flush();
}
} catch (IOException e) {
e.printStackTrace();
}
}