读取含有BOM头的文件遇到的问题
需求是读取一个csv文件,然后解析成对应的数据结构。csv必须包含指定的某些列,通过列名header来进行校验。
解析配置文件的方法。
public List<QuestionData> buildConfigData(final MultipartFile file) {
CsvReader csvReader = null;
List<QuestionData> questionDataList;
try (DataInputStream inputStream = new DataInputStream(file.getInputStream())) {
csvReader = new CsvReader(new InputStreamReader(inputStream, Charset.forName("UTF-8")));
if (!csvReader.readHeaders()) {
return Lists.newLinkedList();
}
final String[] headers = csvReader.getHeaders();
getAndCheckHeader(headers);
questionDataList = getQuestionData(csvReader, headers);
} catch (final IOException e) {
log.error("解析配置文件错误", e);
throw new FatalException("解析配置文件错误");
} finally {
if (csvReader != null) {
csvReader.close();
}
}
return questionDataList;
}
其中,检查header的方法:
private static final Set<String> NEEDED_COLUMNS = ImmutableSet
.of(QuestionDataType.ORDER.name(), QuestionDataType.DESC.name(), QuestionDataType.OPTION_A.name(),
QuestionDataType.OPTION_B.name(), QuestionDataType.OPTION_C.name(), QuestionDataType.ANSWER.name()); private void getAndCheckHeader(final String[] headers) {
//某些必要的列不存在
HashSet<String> sets = Sets.newHashSet(headers);
if (!sets.containsAll(NEEDED_COLUMNS)) {
throw new FatalException("缺少必要的列信息");
}
}
实际出现的问题是,上传文件的时候总是出现缺少必要的列信息这个异常。debug发现,containsAll这个方法一直返回false,但是看NEEDED_COLUMNS里面的字符串,在header里面都存在,例如ORDER字符串:

从这里看,headers里面有ORDER字符串,但是NEEDED_COLUMNS.contains(headers[0])返回的结果就是false。
debug时使用evaluate,将headers[0]的value copy一下,粘贴到输入框里,就发现了问题:

可以看的出来,headers[0]的实际值是"\uFEFFORDER",而非"ORDER",前面多了一个"\uFEFF"。
经查,"\uFEFF"是BOM头,windows下保存文件时经常会插入在字符串最前面,debug时直接看值是看不出来有这个BOM头的。
解决方案,使用apache的BOMInputStream,可以过滤掉BOM头:
public List<QuestionData> buildConfigData(final MultipartFile file) {
CsvReader csvReader = null;
List<QuestionData> questionDataList;
//过滤BOM头
try (BOMInputStream inputStream = new BOMInputStream(file.getInputStream())) {
csvReader = new CsvReader(new InputStreamReader(inputStream, Charset.forName("UTF-8")));
if (!csvReader.readHeaders()) {
return Lists.newLinkedList();
}
final String[] headers = csvReader.getHeaders();
getAndCheckHeader(headers);
questionDataList = getQuestionData(csvReader, headers);
} catch (final IOException e) {
log.error("解析配置文件错误", e);
throw new FatalException("解析配置文件错误");
} finally {
if (csvReader != null) {
csvReader.close();
}
}
return questionDataList;
}
使用BOMInputStream,将原有的InputSteam包一层即可。
参考文章:Java处理文件BOM头的方式推荐
读取含有BOM头的文件遇到的问题的更多相关文章
- linux下查找包含BOM头的文件和清除BOM头命令
查找包含BOM头的文件,命令如下: grep -r -I -l $'^\xEF\xBB\xBF' ./ 这条命令会查找当前目录及子目录下所有包含BOM头的文件,并把文件名在屏幕上输出. 但 ...
- Linux下查找包含BOM头的文件和清除BOM头命令 2014-08-16 12:30:50
Linux下查找包含BOM头的文件和清除BOM头命令 2014-08-16 12:30:50 分类: 系统运维 查找包含BOM头的文件,命令如下: 点击(此处)折叠或打开 grep -r -I -l ...
- python学习——读取染色体长度(六:读取含有染色体长度的文件)
含有染色体长的文件chr_len.txt chr1 10chr2 20chr3 30chr4 40chr5 50 python脚本 #传递命令行参数 import sys # 导入模块 # 从命令行获 ...
- 檢查php文件中是否含有bom的php文件
原文链接: http://www.cnblogs.com/Athrun/archive/2010/05/27/1745464.html 另一篇文章:<关于bom.php>,http://h ...
- 检测文件是否有BOM 头,并删除BOM头(php)
将下面文件放在网站根目录访问即可,它会遍历当前目录下所有子目录,检测文件是否含有BOM头,并删除BOM头 <?php //remove the utf-8 boms //by magicbug ...
- Java处理文件BOM头的方式推荐
背景: java普通的文件读取方式对于bom是无法正常识别的. 使用普通的InputStreamReader,如果采用的编码正确,那么可以获得正确的字符,但bom仍然附带在结果中,很容易导致数据处理出 ...
- C#写UTF8文件时指定是否含BOM头
BOM的基本概念 在UCS 编码中有一个叫做"ZERO WIDTH NO-BREAK SPACE"的字符,它的编码是FEFF.而FFFE在UCS中是不存在的字符,所以不应该出现在实 ...
- PHP批量去除文件BOM头
auto 是否自动替换 默认否 dir 检查目录 默认./ display 是否显示所有文件 默认只显示有bom头的文件 <?php empty($_GET['auto']) && ...
- C#·对于BOM头之完全解决方案
阅文时长 | 0.46分钟 字数统计 | 798.4字符 主要内容 | 1.引言&背景 2.使用C#写入带有/不带有BOM头的文件? 3.对于读取文件时,避免BOM头造成的异常. 4.声明与参 ...
随机推荐
- 重置CentOS 7的Root密码
centos7与centos6有很多修改,不一样了,打算写几篇关于日常用到的改动 修改root密码 centos7的用户模式跟6有所不同 1 - 在启动grub菜单,选择编辑选项启动 2 - 按键盘e ...
- all,any函数
all函数:当矩阵全为非零元素时返回1,否则(存在零元素),返回0: any函数:当矩阵中存在非零 1 1 1 1 1 1 1 1 ...
- JavaSE基础篇—流程控制语句—方法的定义 调用和重载
1.定义方法 是封装在一起来执行操作语句的集合,用来完成某个功能操作,简单的说就是提取出来的有特定功能的代码(程序).在某些语言中被称为函数或者过程,比较特殊的方法是main方法(主方法),main方 ...
- MySQL--pt-osc工具学习
##=====================================================##pt-osc之工作流程:1.检查更改表是否有主键或唯一索引,是否有触发器2.检查修改表 ...
- asp.net 发布程序到iis后无法连接到oralce数据库问题
在应用程序池里面,选中你的站点所使用的应用程序池->高级设置->启用32位应用程序->true
- Cypher查询语言--Neo4j 综合(四)
目录 返回节点 返回关系 返回属性 带特殊字符的标识符 列的别名 可选属性 特别的结果 查询中的返回部分,返回途中定义的感兴趣的部分.可以为节点.关系或其上的属性. 图 返回节点 返回一个节点,在 ...
- 为MySQL选择合适的备份方式[转]
原文链接:http://nettedfish.sinaapp.com/blog/2013/05/31/choose-suitable-backup-strategy-for-mysql/ 数据库的备份 ...
- cglib应用
JDK的动态代理,经常被用来动态地创建对象的代理.JDK的动态代理用起来非常简单,但是有一个限制,就是使用动态代理的对象必须实现一个或多个接口.如果想代理没有实现接口,还可以使用cglib包来完成代理 ...
- JS代码中加上alert才能正常显示效果
模拟一个生成验证码的效果,发现JS代码中加上alert可以正常刷新,没有alert时图片就会丢失,找到解决方法,但是还不是很明白,先记录下来. 生成验证码的servlet代码如下: package s ...
- HDU 3944 DP? [Lucas定理 诡异的预处理]
DP? Time Limit: 10000/3000 MS (Java/Others) Memory Limit: 128000/128000 K (Java/Others)Total Subm ...