字节顺序标记在Java中破坏了文件读取

我正在尝试使用Java读取CSV文件。有些文件的开头可能有字节顺序标记,但不是全部。当存在时,字节顺序将与第一行的其余部分一起读取,从而导致字符串比较出现问题

有没有一种简单的方法可以跳过字节顺序标记

编辑:我在GitHub上发布了一个合适的版本:https://github.com/gpakosz/UnicodeBOMInputStream


这是我不久前编写的一个类,我只是在粘贴之前编辑了包名。没什么特别的,它与SUN的bug数据库中发布的解决方案非常相似。把它加入到你的代码中,你就没事了

/*____________________________________________________________________________
* 
*文件:UnicodeBOMInputStream.java
*作者:Gregory Pakosz。
*日期:2005年11月2日
* ____________________________________________________________________________
*/
包com.stackoverflow.answer;
导入java.io.IOException;
导入java.io.InputStream;
导入java.io.PushbackInputStream;
/**
*这个<代码>Unicode数据流&lt/代码>类包装任何
*<代码>输入流&lt/代码>并检测是否存在任何Unicode BOM
*(字节顺序标记)在其开头,如
*<a href=”http://www.faqs.org/rfcs/rfc3629.html“>rfc3629-UTF-8,一种iso10646&lt/a>
* 
*<p>这个
*<a href=”http://www.unicode.org/unicode/faq/utf_bom.html“>Unicode常见问题解答&lt/a>
*定义了5种BOM类型:<ul>
*<李&gt&书信电报;预处理>00 FE FF=UTF-32,大端头&lt/预处理&gt&lt/李>
*<李&gt&书信电报;预处理>FF FE 00 00=UTF-32,小端头&lt/预处理&gt&lt/李>
*<李&gt&书信电报;预处理>FE FF=UTF-16,大端值&lt/预处理&gt&lt/李>
*<李&gt&书信电报;预处理>FF FE=UTF-16,小端头&lt/预处理&gt&lt/李>
*<李&gt&书信电报;预处理>EF BB BF=UTF-8&lt/预处理&gt&lt/李>
*&lt/ul&gt&lt/p>
* 
*<p>使用{@link#getBOM()}方法了解是否已检测到BOM
*或者不是。
*&lt/p>
*<p>使用{@link#skipBOM()}方法从数据库中删除检测到的BOM表
*包装<代码>输入流&lt/代码>反对。&lt/p>
*/
公共类UnicodeBOMInputStream扩展了InputStream
{
/**
*描述不同Unicode类型的类型安全枚举类
*博姆斯。
*/
公共静态最终类BOM
{
/**
*没有。
*/
公共静态最终BOM无=新BOM(新字节[]{},“无”);
/**
*UTF-8物料清单(EF BB BF)。
*/
公共静态最终BOM UTF_8=新BOM(新字节[]{(字节)0xEF,
(字节)0xBB,
(字节)0xBF},
“UTF-8”);
/**
*UTF-16,小端(FF FE)。
*/
公共静态最终BOM UTF_16_LE=新BOM(新字节[]{(字节)0xFF,
(字节)0xFE},
“UTF-16 little endian”);
/**
*UTF-16,大端(FE-FF)。
*/
公共静态最终BOM UTF_16_BE=新BOM(新字节[]{(字节)0xFE,
(字节)0xFF},
“UTF-16 big-endian”);
/**
*UTF-32,小端(FF FE 00)。
*/
公共静态最终BOM UTF_32_LE=新BOM(新字节[]{(字节)0xFF,
(字节)0xFE,
(字节)0x00,
(字节)0x00},
“UTF-32 little endian”);
/**
*UTF-32,大端(00 FE FF)。
*/
公共静态最终BOM UTF_32_BE=新BOM(新字节[]{(字节)0x00,
(字节)0x00,
(字节)0xFE,
(字节)0xFF},
“UTF-32大端接口”);
/**
*返回此物料清单的<代码>字符串</code>表示形式<代码></code>
*价值观。
*/
公共最终字符串toString()
{
返回说明;
}
/**
*返回与此<代码>BOM</code>值对应的字节。
*/
公共最终字节[]getBytes()
{
最终整数长度=bytes.length;
最终字节[]结果=新字节[长度];
//抄袭
数组复制(字节,0,结果,0,长度);
返回结果;
}
专用BOM表(最终字节BOM[],最终字符串描述)
{
断言(bom!=null):“无效bom:不允许为null”;
断言(description!=null):“无效描述:不允许null”;
断言(description.length()!=0):“描述无效:不允许使用空字符串”;
this.bytes=bom;
this.description=描述;
}
最终字节[];
私有最终字符串描述;
}//物料清单
/**
*构造一个新的<code>Unicode数据流</code>来包装
*指定的<代码>输入流</code>。
* 
*@param inputStream一个<代码>inputStream</code>。
* 
*当<code>inputStream</code>被禁用时,@引发NullPointerException
*<代码>空</code>。
*@从指定的<代码>输入流</code>读取时引发IOException;
*尝试检测Unicode BOM表时。
*/
公共UnicodeBOMInputStream(最终InputStream InputStream)抛出NullPointerException,
IOException
{
如果(inputStream==null)
抛出新的NullPointerException(“无效输入流:不允许null”);
in=新的PushbackInputStream(inputStream,4);
最终字节bom[]=新字节[4];
最终整型读数=整型读数(bom);
开关(读取)
{
案例4:
如果((bom[0]==(字节)0xFF)&
(bom[1]==(字节)0xFE)和;
(物料清单[2]==(字节)0x00)&
(bom[3]==(字节)0x00)
{
this.bom=bom.UTF_32_LE;
打破
}
其他的
如果((物料清单[0]==(字节)0x00)&
(物料清单[1]==(字节)0x00)&
(物料清单[2]==(字节)0xFE)&
(bom[3]==(字节)0xFF)
{
this.bom=bom.UTF_32_BE;
打破
}
案例3:
如果((bom[0]==(字节)0xEF)&&
(物料清单[1]==(字节)0xBB)&
(bom[2]==(字节)0xBF)
{
this.bom=bom.UTF_8;
打破
}
案例2:
如果((bom[0]==(字节)0xFF)&
(bom[1]==(字节)0xFE)
{
this.bom=bom.UTF_16_LE;
打破
}
其他的
如果((bom[0]==(字节)0xFE)&&
(bom[1]==(字节)0xFF)
{
this.bom=bom.UTF_16_BE;
打破
}
违约:
this.bom=bom.NONE;
打破
}
如果(读取>0)
in.未读(物料清单,0,已读);
}
/**
*返回包装中检测到的<代码>BOM</code&gt
*<代码>输入流</code>对象。
* 
*@返回一个<代码>物料清单</code>值。
*/
公共最终BOM getBOM()
{
//BOM表类型是不可变的。
返回bom;
}
/**
*跳过包装中找到的<代码>BOM</code&gt
*<代码>输入流</code>对象。
* 
*@返回此<代码>数据流</code>。
* 
*@尝试从包装中跳过BOM表时引发IOException
*<代码>输入流</code>对象。
*/
公共最终同步UnicodeBOMInputStream skipBOM()引发IOException
{
如果(!跳过)
{
in.skip(bom.bytes.length);
跳过=真;
}
归还这个;
}
/**
*{@inheritardoc}
*/
public int read()引发IOException
{
返回in.read();
}
/**
*{@inheritardoc}
*/
public int read(最终字节b[])引发IOException,
空指针异常
{
返回in.read(b,0,b.length);
}
/**
*{@inheritardoc}
*/
公共整数读取(最终字节b[],
最终整型关闭,
final int len)引发IOException,
空指针异常
{
返回。读取(b,关闭,len);
}
/**
*{@inheritardoc}
*/
公共长跳过(最终长n)引发IOException
{
返回。跳过(n);
}
/**
*{@inheritardoc}
*/
public int available()引发IOException
{
返回in.available();
}
/**
*{@inheritardoc}
*/
public void close()引发IOException
{
in.close();
}
/**
*{@inheritardoc}
*/
公共同步无效标记(最终整型读取限制)
{
in.标记(readlimit);
}
/**
*{@inheritardoc}
*/
public synchronized void reset()引发IOException
{
in.reset();
}
/**
*{@inheritardoc}
*/
公共布尔标记受支持()
{
在.markSupported()中返回;
}
私有最终PushbackInputStream输入;
私人最终物料清单;
私有布尔值=false;
}//Unicode数据流

你是这样使用它的:

导入java.io.BufferedReader;
导入java.io.FileInputStream;
导入java.io.InputStreamReader;
公共最终类UnicodePutStreamUsage
{
公共静态void main(最终字符串[]args)引发异常
{
FileInputStream fis=新的FileInputStream(“test/officing_bom.txt”);
UnicodeBOMInputStream ubis=新的UnicodeBOMInputStream(fis);
System.out.println(“检测到的BOM:+ubis.getBOM());
System.out.print(“在不跳过BOM的情况下读取文件内容:”;
InputStreamReader isr=新的InputStreamReader(ubis);
BufferedReader br=新

发表评论