Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/349.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java Spring返回以UTF-8编码并带有BOM的CSV文件_Java_Spring_Utf 8_Byte Order Mark - Fatal编程技术网

Java Spring返回以UTF-8编码并带有BOM的CSV文件

Java Spring返回以UTF-8编码并带有BOM的CSV文件,java,spring,utf-8,byte-order-mark,Java,Spring,Utf 8,Byte Order Mark,显然,为了让excel能够很好地打开CSV文件,它应该在开头有字节顺序标记。CSV的下载是通过写入控制器中HttpServletResponse的输出流来实现的,因为数据是在请求期间生成的。当我尝试写入BOM字节时出现异常-java.io.CharConversionException:不是ISO 8859-1字符:[(即使我指定的编码是UTF-8) 控制器的方法有问题 @RequestMapping("/monthly/list") public List<MonthlyDetails

显然,为了让excel能够很好地打开CSV文件,它应该在开头有字节顺序标记。CSV的下载是通过写入控制器中
HttpServletResponse
的输出流来实现的,因为数据是在请求期间生成的。当我尝试写入BOM字节时出现异常-
java.io.CharConversionException:不是ISO 8859-1字符:[
(即使我指定的编码是
UTF-8


控制器的方法有问题

@RequestMapping("/monthly/list")
public List<MonthlyDetailsItem> queryDetailsItems(
        MonthlyDetailsItemQuery query,
        @RequestParam(value = "format", required = false) String format,
        @RequestParam(value = "attachment", required = false, defaultValue="false") Boolean attachment,
        HttpServletResponse response) throws Exception 
{   
    // load item list
    List<MonthlyDetailsItem> list = detailsSvc.queryMonthlyDetailsForList(query);
    // adjust format
    format = format != null ? format.toLowerCase() : "json";
    if (!Arrays.asList("json", "csv").contains(format)) format = "json";

    // modify common response headers
    response.setCharacterEncoding("UTF-8");
    if (attachment)
        response.setHeader("Content-Disposition", "attachment;filename=duomenys." + format);

    // build csv
    if ("csv".equals(format)) {
        response.setContentType("text/csv; charset=UTF-8");
        response.getOutputStream().print("\ufeff");
        response.getOutputStream().write(buildMonthlyDetailsItemCsv(list).getBytes("UTF-8"));
        return null;
    }

    return list;
}
@RequestMapping(“/monthly/list”)
公共列表查询站点(
MonthlyDetailsItemQuery查询,
@RequestParam(value=“format”,required=false)字符串格式,
@RequestParam(value=“附件”,required=false,defaultValue=“false”)布尔附件,
HttpServletResponse)引发异常
{   
//加载项列表
List List=detailsSvc.queryMonthlyDetailsForList(查询);
//调整格式
format=format!=null?format.toLowerCase():“json”;
如果(!Arrays.asList(“json”,“csv”).contains(format))format=“json”;
//修改公共响应头
响应。setCharacterEncoding(“UTF-8”);
如有需要(附件)
setHeader(“内容处置”、“附件;文件名=duomeys.”+格式);
//构建csv
如果(“csv”.等于(格式)){
response.setContentType(“text/csv;charset=UTF-8”);
response.getOutputStream().print(“\ufeff”);
response.getOutputStream().write(buildMonthlyDetailsItemCsv(list.getBytes(“UTF-8”));
返回null;
}
退货清单;
}

这没有多大意义:BOM是针对UTF-16的;UTF-8没有字节顺序。使用setCharacterEncoding设置的编码用于getWriter,而不是getOutputStream

更新:

好的,试试这个:

if ("csv".equals(format)) {
    response.setContentType("text/csv; charset=UTF-8");
    PrintWriter out = response.getWriter();
    out.print("\uFEFF");
    out.print(buildMonthlyDetailsItemCsv(list));
    return null;
}

我假设buildMonthlyDetailsItemCsv方法返回一个字符串。

我刚刚遇到同样的问题。对我来说,有效的解决方案是从响应对象获取输出流并按如下方式写入

    // first create an array for the Byte Order Mark
    final byte[] bom = new byte[] { (byte) 239, (byte) 187, (byte) 191 }; 
    try (OutputStream os = response.getOutputStream()) {
        os.write(bom);

        final PrintWriter w = new PrintWriter(new OutputStreamWriter(os, "UTF-8"));
        w.print(data);
        w.flush();
        w.close();
    } catch (IOException e) {
        // logit
    }
因此,在OutputStreamWriter上指定了UTF-8


作为补充,我应该补充,同样的应用程序需要允许用户上传文件,这些文件可能有也可能没有BOM。这可以通过使用类
org.apache.commons.io.input.BOMInputStream
来处理,然后使用该类构造
org.apache.commons.csv.CSVParser
。 BOMInputStream包含一个方法
hasBOM()
,用于检测文件是否有BOM。 我首先遇到的一个问题是
hasBOM()
方法从底层流中读取(显然!),因此处理这个问题的方法是首先标记流,然后在测试之后,如果它没有BOM,则重置流。我为此使用的代码如下所示:

try(InputStream=uploadFile.getInputStream();
BufferedInputStream buffIs=新的BufferedInputStream(is);
BOMInputStream bomIn=新的BOMInputStream(buffIs);){
buffIs.mark(前向长度);
//这将使我们能够处理有无BOM的csv
最终布尔值hasBOM=bomIn.hasBOM();
最终BufferedReader buffReadr=新的BufferedReader(
新的InputStreamReader(hasBOM?bomIn:buffIs,StandardCharsets.UTF_8));
//如果该流没有BOM,那么我们必须将该流重置为测试
//对于BOM表,将消耗一些字节
如果(!hasBOM){
buffIs.reset();
}
//收集已验证的实体详细信息
final CSVParser parser=CSVParser.parse(buffReadr,
CSVFormat.DEFAULT.withFirstRecordAsHeader());
//使用解析器做一些事情
...
//抓捕和清理

希望这对其他人有所帮助。

您可以尝试
response.getOutputStream().write(“\ufeff.getBytes”(“UTF-8”))
对于BOM部分?这不是真的。请参阅。有一个为UTF-8定义的BOM,但它不是强制性的。唉,Java无法自动处理UTF-8 BOM。@vanje嗯,UTF-8编码没有用。可能是的。但这不是重点。有时你必须处理它。是否没有用。关于我的答案,我必须处理fi由Excel创建的具有BOM的LE,我解释的过程对我有效。@MauricePerry BOM值不是UTF8,因此被UTF8忽略,我怀疑这就是为什么它被用作元数据(我猜)Excel的值。但是程序仍然需要处理它。这确实帮助了我,但我发现我必须编写两次bom,否则它将不会出现在保存的CSV文件中。不确定原因。可能第一个由浏览器使用,第二个保存到用户计算机上的CSV文件中。这在4种不同的浏览器中是一致的。