读取含有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.声明与参 ...
随机推荐
- redis发布与订阅
发布与订阅 除了实现任务队列外, Redis还提供了一组命令可以让开发者实现"发布/订阅"(publish/subscribe)模式. "发布/订阅"模式同样可 ...
- Markdown内嵌Html语言
概述 Markdown是内嵌Html语言的,这使得我们可以在Markdown文档里面实现很多有趣的东西.现在记录在此,供自己以后参考,相信对其他人也有用. 介绍 Markdown的语法只有一个目标:作 ...
- 理解DNS
理解DNS 写在前面: 目前,我们大部分的网络通信都是基于TCP/IP协议的,而TCP/IP又基于IP地址作为唯一标识进行通信,随着需要记忆的IP地址数量的增多,肯定会超出我们的记忆能力范围,但如果使 ...
- Java:对象的强、软、弱和虚引用[转]
原文链接:http://zhangjunhd.blog.51cto.com/113473/53092/ 原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法 ...
- python实现时间o(1)的最小栈
这是毕业校招二面时遇到的手写编程题,当时刚刚开始学习python,整个栈写下来也是费了不少时间.毕竟语言只是工具,只要想清楚实现,使用任何语言都能快速的写出来. 何为最小栈?栈最基础的操作是压栈(pu ...
- Vue的生命周期
1.1.实例生命周期 每个 Vue 实例在被创建之前都要经过一系列的初始化过程.例如需要设置数据监听.编译模板.挂载实例到 DOM.在数据变化时更新 DOM 等.同时在这个过程中也会运行一些叫做生命周 ...
- 在Android上编写模块化项目(翻译)
来源博客:Wang Jie's Blog 本文链接:http://blog.wangjiegulu.com/2018/02/13/writing_a_modular_project_on_androi ...
- 2018/2/13 ElasticSearch学习笔记三 自动映射以及创建自动映射模版,ElasticSearch聚合查询
终于把这些命令全敲了一遍,话说ELK技术栈L和K我今天花了一下午全部搞定,学完后还都是花式玩那种...E却学了四天(当然主要是因为之前上班一直没时间学,还有安装服务时出现的各种error真是让我扎心了 ...
- ThinkPHP删除栏目(单)
当我们做一些网站项目的时候,都会遇到这样一类问题,删除一个栏目,而这个栏目又不是最底层栏目,也就是说,被删除的栏目拥有子栏目,这时,我们执行删除该栏目的命令,就需要将该栏目及其子栏目一并删除,因为我们 ...
- Git教程:
使用前配置: git init git config --global user.name "yanpeng1314" git config --global user.email ...