显然,excel可以很好地打开CSV文件,它应该在开始时有字节顺序标记。通过在控制器中写入HttpServletResponse
的输出流来实现CSV的下载,因为在请求期间生成数据。当我尝试编写BOM字节时出现异常 - java.io.CharConversionException: Not an ISO 8859-1 character: []
(即使我指定的编码是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;
}
答案 0 :(得分:1)
我碰到过同样的问题。对我有用的解决方案是从响应对象获取输出流,并按如下所示对其进行写入
// 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 is = uploadFile.getInputStream();
BufferedInputStream buffIs = new BufferedInputStream(is);
BOMInputStream bomIn = new BOMInputStream(buffIs);) {
buffIs.mark(LOOKAHEAD_LENGTH);
// this should allow us to deal with csv's with or without BOMs
final boolean hasBOM = bomIn.hasBOM();
final BufferedReader buffReadr = new BufferedReader(
new InputStreamReader(hasBOM ? bomIn : buffIs, StandardCharsets.UTF_8));
// if this stream does not have a BOM, then we must reset the stream as the test
// for a BOM will have consumed some bytes
if (!hasBOM) {
buffIs.reset();
}
// collect the validated entity details
final CSVParser parser = CSVParser.parse(buffReadr,
CSVFormat.DEFAULT.withFirstRecordAsHeader());
// Do stuff with the parser
...
// Catch and clean up
希望这对某人有帮助。
答案 1 :(得分:-1)
它没有多大意义:BOM是针对UTF-16的; UTF-8没有字节顺序。您使用setCharacterEncoding设置的编码用于getWriter,而不是用于getOutputStream。
更新:
好的,试试这个:
Sub MyVariable()
Select Case Range("A1").Value
Case 1 to 150:
MsgBox Range("A1")
Case Else:
'nothing
End Select
End Sub
我假设方法buildMonthlyDetailsItemCsv返回一个String。