java - OpenCSV 在 Java 中一起读取附加字节值和第一行的第一个值
问题描述
我正在做一个项目,我们使用 OpenCSV 读取 CSV 文件并在开始时用它们填充数据库。我注意到有一件奇怪的事情,在某些情况下无法查询给定的标识符值。在调试过程中,我发现 OpenCSV 没有正确读取 CSV。
假设我有以下 CSV 文件:
01;foo
02;bar
...
示例中的第一行也是真实 CSV 文件中的第一行。该文件以 UTF-8 编码。以下代码用于读取值:
try (CSVReader csvReader = CSVUtils.createCSVReader(masterDataCSVPath, csvDelimiter)) {
List<String[]> masterData = csvReader.readAll();
}
创建的代码csvReader
:
static private CSVParser createCSVParser(String CSVDelimiter) {
return new CSVParserBuilder().withSeparator(CSVDelimiter.charAt(0)).build();
}
static public CSVReader createCSVReader(String CSVPath, String CSVDelimiter) throws FileNotFoundException {
return new CSVReaderBuilder(new FileReader(CSVPath)).withCSVParser(createCSVParser(CSVDelimiter)).build();
}
当我使用以下代码读取 CSV 文件时,在调试期间我得到以下字节值01
:
但是,如果我将 CSV 文件更改为(注意顶部的换行符):
01;foo
02;bar
...
读入的数据变为:
在这种情况下,“一切都很好”,如果我删除masterData
列表中的第一项,我可以“正确”读取值。但是,这不是一个干净的解决方案:
- 它引出了一个问题:为什么会发生这种情况?
- 另外,我不认为我们应该解决这个问题而不是解决它。仅当我的源 CSV 开头有换行符时才提供此功能。
所以我恳请帮助,如何减轻这种情况?
解决方案
这不是 OpenCSV 特定的问题,而是FileReader
读取 UTF 编码文件中的 BOM。这有点出乎意料,但这是有道理的,因为没有上下文FileReader
可以排除这些字节。
解决方案是手动删除它,或者 - 在我的情况下 - 使用库来确保它被排除在外。我编写了以下实用程序类:
public class CSVUtils {
private static CSVParser createCSVParser(final String CSVDelimiter) {
return new CSVParserBuilder().withSeparator(CSVDelimiter.charAt(0)).build();
}
private static BOMInputStream versatileBOMInputStreamGenerator(final InputStream inputStream) {
return new BOMInputStream(inputStream, ByteOrderMark.UTF_8, ByteOrderMark.UTF_16BE, ByteOrderMark.UTF_16LE,
ByteOrderMark.UTF_16BE, ByteOrderMark.UTF_32LE, ByteOrderMark.UTF_32BE);
}
public static CSVReader createCSVReaderFromFile(final String CSVPath, final String CSVDelimiter) throws FileNotFoundException {
return new CSVReaderBuilder(new InputStreamReader(
versatileBOMInputStreamGenerator(new FileInputStream(CSVPath)), StandardCharsets.UTF_8))
.withCSVParser(createCSVParser(CSVDelimiter)).build();
}
public static CSVReader createCSVReaderFromString(final String content, final String CSVDelimiter) {
byte[] contentBytes = content.getBytes(StandardCharsets.UTF_8);
return new CSVReaderBuilder(new InputStreamReader(
versatileBOMInputStreamGenerator(new ByteArrayInputStream(contentBytes)), StandardCharsets.UTF_8))
.withCSVParser(createCSVParser(CSVDelimiter)).build();
}
}
我所要做的就是CSVReader
稍后在需要时使用这些创建的对象。如您所见,它使用了一些依赖项,可以使用
import org.apache.commons.io.ByteOrderMark;
import org.apache.commons.io.input.BOMInputStream;
这些依赖项可以通过 POM 添加到项目中,如下所示:
<!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.11.0</version>
推荐阅读
- android - 错误:无法在 android studio 中访问 zzbgl
- reactjs - onChange 或 onBlur 来改变 ReactJs 中的状态?
- sql-server - 存储过程变量声明
- google-cloud-sql - 谷歌云SQL二代| MySQL 服务器正在使用 --read-only 选项运行,因此它无法执行此语句
- jquery - jQuery 链接列表
- javascript - jquery 没有在 localhost 内的服务器上正确加载,工作正常
- android - 为什么 Firebase 全局导入比特定导入更轻?
- javascript - 保护/隐藏 PDF 中嵌入的 JavaScript
- bootstrap-4 - 重叠 div 以显示内容(在中心)和(在右侧)侧
- python - OSError: [WinError 10056] 在已连接的套接字上发出了连接请求