读取UTF-8 – BOM标记
我正在通过FileReader读取文件 – 文件是UTF-8解码(与BOM)现在我的问题是:我读取文件并输出一个string,但遗憾的是BOM标记也输出了。 为什么会发生?
fr = new FileReader(file); br = new BufferedReader(fr); String tmp = null; while ((tmp = br.readLine()) != null) { String text; text = new String(tmp.getBytes(), "UTF-8"); content += text + System.getProperty("line.separator"); }
在第一行之后输出
?<style>
在Java中,您必须手动使用UTF8 BOM(如果存在)。 此行为在Java错误数据库中logging, 在这里和这里 。 现在不会有任何修复,因为它会破坏JavaDoc或XMLparsing器等现有工具。 Apache IO Commons提供了一个BOMInputStream
来处理这种情况。
看看这个解决scheme: 用BOM处理UTF8文件
最简单的解决方法可能只是从string中删除所产生的\uFEFF
,因为出于其他原因极不可能出现。
tmp = tmp.replace("\uFEFF", "");
另请参阅此番石榴虫报告
使用Apache Commons库 。
类: org.apache.commons.io.input.BOMInputStream
用法示例:
String defaultEncoding = "UTF-8"; InputStream inputStream = new FileInputStream(someFileWithPossibleUtf8Bom); try { BOMInputStream bOMInputStream = new BOMInputStream(inputStream); ByteOrderMark bom = bOMInputStream.getBOM(); String charsetName = bom == null ? defaultEncoding : bom.getCharsetName(); InputStreamReader reader = new InputStreamReader(new BufferedInputStream(bOMInputStream), charsetName); //use reader } finally { inputStream.close(); }
以下是我如何使用Apache BOMInputStream,它使用try-with-resources块。 “false”参数告诉对象忽略以下BOM(出于安全原因,我们使用“BOM-less”文本文件,哈哈):
try( BufferedReader br = new BufferedReader( new InputStreamReader( new BOMInputStream( new FileInputStream( file), false, ByteOrderMark.UTF_8, ByteOrderMark.UTF_16BE, ByteOrderMark.UTF_16LE, ByteOrderMark.UTF_32BE, ByteOrderMark.UTF_32LE ) ) ) ) { // use br here } catch( Exception e) }
这里提到,这通常是Windows上的文件的问题。
一个可能的解决scheme是通过像dos2unix这样的工具首先运行该文件。
使用Apache Commons IO 。
例如,让我们来看看我的代码(用于读取拉丁文和西里尔字符的文本文件):
String defaultEncoding = "UTF-16"; InputStream inputStream = new FileInputStream(new File("/temp/1.txt")); BOMInputStream bomInputStream = new BOMInputStream(inputStream); ByteOrderMark bom = bomInputStream.getBOM(); String charsetName = bom == null ? defaultEncoding : bom.getCharsetName(); InputStreamReader reader = new InputStreamReader(new BufferedInputStream(bomInputStream), charsetName); int data = reader.read(); while (data != -1) { char theChar = (char) data; data = reader.read(); ari.add(Character.toString(theChar)); } reader.close();
因此,我们有一个名为“ari”的ArrayList,其中除了BOM之外的所有字符都来自文件“1.txt”。
然后我想出了这个Reader子类
/* * Copyright (C) 2016 donizyo * */ package net.donizyo.io; public class BOMReader extends BufferedReader { public static final String DEFAULT_ENCODING = "UTF-8"; public BOMReader(File file) throws IOException { this(file, DEFAULT_ENCODING); } private BOMReader(File file, String encoding) throws IOException { this(new FileInputStream(file), encoding); } private BOMReader(FileInputStream input, String encoding) throws IOException { this(new BOMInputStream(input), encoding); } private BOMReader(BOMInputStream input, String encoding) throws IOException { super(new InputStreamReader(input, getCharset(input, encoding))); } private static String getCharset(BOMInputStream bomInput, String encoding) throws IOException { ByteOrderMark bom; bom = bomInput.getBOM(); return bom == null ? encoding : bom.getCharsetName(); } }
我发现绕过BOM的最简单的方法
BufferedReader br = new BufferedReader(new InputStreamReader(fis)); while ((currentLine = br.readLine()) != null) { //case of, remove the BOM of UTF-8 BOM currentLine = currentLine.replace("","");
不知道你认为你用tmp.getBytes()和“UTF-8”等来实现
我很确定Java不支持BOM,虽然我找不到现在说的文档。
值得一提的是, UTF-8中的BOM是毫无意义的 ,因为标准规定了字节顺序而不考虑硬件。 所以,如果你能阻止他们在第一时间产生,这可能会有所帮助。