需求是读取一个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头的文件遇到的问题的更多相关文章

  1. linux下查找包含BOM头的文件和清除BOM头命令

    查找包含BOM头的文件,命令如下:   grep -r -I -l $'^\xEF\xBB\xBF' ./   这条命令会查找当前目录及子目录下所有包含BOM头的文件,并把文件名在屏幕上输出.   但 ...

  2. Linux下查找包含BOM头的文件和清除BOM头命令 2014-08-16 12:30:50

    Linux下查找包含BOM头的文件和清除BOM头命令 2014-08-16 12:30:50 分类: 系统运维 查找包含BOM头的文件,命令如下: 点击(此处)折叠或打开 grep -r -I -l ...

  3. python学习——读取染色体长度(六:读取含有染色体长度的文件)

    含有染色体长的文件chr_len.txt chr1 10chr2 20chr3 30chr4 40chr5 50 python脚本 #传递命令行参数 import sys # 导入模块 # 从命令行获 ...

  4. 檢查php文件中是否含有bom的php文件

    原文链接: http://www.cnblogs.com/Athrun/archive/2010/05/27/1745464.html 另一篇文章:<关于bom.php>,http://h ...

  5. 检测文件是否有BOM 头,并删除BOM头(php)

    将下面文件放在网站根目录访问即可,它会遍历当前目录下所有子目录,检测文件是否含有BOM头,并删除BOM头 <?php //remove the utf-8 boms //by magicbug ...

  6. Java处理文件BOM头的方式推荐

    背景: java普通的文件读取方式对于bom是无法正常识别的. 使用普通的InputStreamReader,如果采用的编码正确,那么可以获得正确的字符,但bom仍然附带在结果中,很容易导致数据处理出 ...

  7. C#写UTF8文件时指定是否含BOM头

    BOM的基本概念 在UCS 编码中有一个叫做"ZERO WIDTH NO-BREAK SPACE"的字符,它的编码是FEFF.而FFFE在UCS中是不存在的字符,所以不应该出现在实 ...

  8. PHP批量去除文件BOM头

    auto 是否自动替换 默认否 dir 检查目录 默认./ display 是否显示所有文件 默认只显示有bom头的文件 <?php empty($_GET['auto']) && ...

  9. C#·对于BOM头之完全解决方案

    阅文时长 | 0.46分钟 字数统计 | 798.4字符 主要内容 | 1.引言&背景 2.使用C#写入带有/不带有BOM头的文件? 3.对于读取文件时,避免BOM头造成的异常. 4.声明与参 ...

随机推荐

  1. 重置CentOS 7的Root密码

    centos7与centos6有很多修改,不一样了,打算写几篇关于日常用到的改动 修改root密码 centos7的用户模式跟6有所不同 1 - 在启动grub菜单,选择编辑选项启动 2 - 按键盘e ...

  2. all,any函数

    all函数:当矩阵全为非零元素时返回1,否则(存在零元素),返回0: any函数:当矩阵中存在非零      1     1     1     1      1     1     1     1 ...

  3. JavaSE基础篇—流程控制语句—方法的定义 调用和重载

    1.定义方法 是封装在一起来执行操作语句的集合,用来完成某个功能操作,简单的说就是提取出来的有特定功能的代码(程序).在某些语言中被称为函数或者过程,比较特殊的方法是main方法(主方法),main方 ...

  4. MySQL--pt-osc工具学习

    ##=====================================================##pt-osc之工作流程:1.检查更改表是否有主键或唯一索引,是否有触发器2.检查修改表 ...

  5. asp.net 发布程序到iis后无法连接到oralce数据库问题

    在应用程序池里面,选中你的站点所使用的应用程序池->高级设置->启用32位应用程序->true

  6. Cypher查询语言--Neo4j 综合(四)

    目录 返回节点 返回关系 返回属性 带特殊字符的标识符 列的别名 可选属性 特别的结果   查询中的返回部分,返回途中定义的感兴趣的部分.可以为节点.关系或其上的属性. 图 返回节点 返回一个节点,在 ...

  7. 为MySQL选择合适的备份方式[转]

    原文链接:http://nettedfish.sinaapp.com/blog/2013/05/31/choose-suitable-backup-strategy-for-mysql/ 数据库的备份 ...

  8. cglib应用

    JDK的动态代理,经常被用来动态地创建对象的代理.JDK的动态代理用起来非常简单,但是有一个限制,就是使用动态代理的对象必须实现一个或多个接口.如果想代理没有实现接口,还可以使用cglib包来完成代理 ...

  9. JS代码中加上alert才能正常显示效果

    模拟一个生成验证码的效果,发现JS代码中加上alert可以正常刷新,没有alert时图片就会丢失,找到解决方法,但是还不是很明白,先记录下来. 生成验证码的servlet代码如下: package s ...

  10. HDU 3944 DP? [Lucas定理 诡异的预处理]

    DP? Time Limit: 10000/3000 MS (Java/Others)    Memory Limit: 128000/128000 K (Java/Others)Total Subm ...