РЕДАКТИРОВАТЬ : Я сделал правильный релиз на GitHub: https://github.com/gpakosz/UnicodeBOMInputStream
Вот класс, который я кодировал некоторое время назад, я просто отредактировал имя пакета перед вставкой. Ничего особенного, это очень похоже на решения, опубликованные в базе данных ошибок SUN. Включите его в свой код, и все в порядке.
<code>/* ____________________________________________________________________________
*
* File: UnicodeBOMInputStream.java
* Author: Gregory Pakosz.
* Date: 02 - November - 2005
* ____________________________________________________________________________
*/
package com.stackoverflow.answer;
import java.io.IOException;
import java.io.InputStream;
import java.io.PushbackInputStream;
/**
* The <code>UnicodeBOMInputStream</code> class wraps any
* <code>InputStream</code> and detects the presence of any Unicode BOM
* (Byte Order Mark) at its beginning, as defined by
* <a href="http://www.faqs.org/rfcs/rfc3629.html">RFC 3629 - UTF-8, a transformation format of ISO 10646</a>
*
* <p>The
* <a href="http://www.unicode.org/unicode/faq/utf_bom.html">Unicode FAQ</a>
* defines 5 types of BOMs:<ul>
* <li><pre>00 00 FE FF = UTF-32, big-endian
*
FF FE 00 00 = UTF-32, little-endian
*
FE FF = UTF-16, big-endian
*
FF FE = UTF-16, little-endian
*
EF BB BF = UTF-8
*
*
*
Используйте метод {@link #getBOM ()}, чтобы узнать, была ли обнаружена спецификация
* или нет.
*
*
Используйте метод {@link #skipBOM ()} для удаления обнаруженной спецификации из
* завернутый InputStream
объект.
* /
открытый класс UnicodeBOMInputStream расширяет InputStream
{
/ **
* Введите безопасный класс перечисления, который описывает различные типы Unicode
* Спецификации.
* /
публичная статическая конечная спецификация класса
{
/ **
* НИКТО.
* /
public static final BOM NONE = новая BOM (новый байт [] {}, "NONE");
/ **
* UTF-8 BOM (EF BB BF).
* /
публичная статическая конечная спецификация UTF_8 = новая спецификация (новый байт [] {(байт) 0xEF,
(Байт) 0xBB,
(Байт) 0xBF},
"UTF-8");
/ **
* UTF-16, little-endian (FF FE).
* /
открытая статическая конечная спецификация UTF_16_LE = новая спецификация (новый байт [] {(байт) 0xFF,
(Байт) 0xFE},
«UTF-16 little-endian»);
/ **
* UTF-16, big-endian (FE FF).
* /
публичная статическая конечная спецификация UTF_16_BE = новая спецификация (новый байт [] {(байт) 0xFE,
(Байт) 0xFF},
«UTF-16 big-endian»);
/ **
* UTF-32 с прямым порядком байтов (FF FE 00 00).
* /
открытая статическая конечная спецификация UTF_32_LE = новая спецификация (новый байт [] {(байт) 0xFF,
(Байт) 0xFE,
(Байт) 0x00,
(Байт) 0x00},
«UTF-32 little-endian»);
/ **
* UTF-32, big-endian (00 00 FE FF).
* /
открытая статическая конечная спецификация UTF_32_BE = новая спецификация (новый байт [] {(байт) 0x00,
(Байт) 0x00,
(Байт) 0xFE,
(Байт) 0xFF},
«UTF-32 big-endian»);
/ **
* Возвращает
String
представление этого
BOM
* значение.
* /
public final String toString ()
{
вернуть описание;
}
/ **
* Возвращает байты, соответствующие этому
BOM
значению.
* /
открытый финальный байт [] getBytes ()
{
final int length = bytes.length;
конечный байт [] результат = новый байт [длина];
// Сделать защитную копию
System.arraycopy (байты, 0, результат, 0, длина);
вернуть результат;
}
частная спецификация (финальный байт [], финальное описание строки)
{
assert (bom! = null): "недопустимая спецификация: null не разрешен";
assert (description! = null): "неверное описание: null не разрешен";
assert (description.length ()! = 0): "неверное описание: пустая строка не допускается";
this.bytes = bom;
this.description = description;
}
последние байты [];
личное финальное описание строки;
} // Спецификация
/ **
* Создает новый
UnicodeBOMInputStream
, который оборачивает
* указано
InputStream
.
*
* @param inputStream an
InputStream
.
*
* @throws NullPointerException, когда
inputStream
*
null
.
* @ выбрасывает IOException при чтении из указанного
InputStream
* при попытке обнаружить спецификацию Unicode.
* /
public UnicodeBOMInputStream (final InputStream inputStream) генерирует исключение NullPointerException,IOException
{
if (inputStream == null)
бросить новое исключение NullPointerException («неверный поток ввода: ноль не разрешен»);
in = new PushbackInputStream (inputStream, 4);
последний байт bom [] = новый байт [4];
final int read = in.read (bom);
Переключатель (чтение)
{
дело 4:
if ((bom [0] == (byte) 0xFF) &&
(bom [1] == (byte) 0xFE) &&
(bom [2] == (byte) 0x00) &&
(bom [3] == (byte) 0x00))
{
this.bom = BOM.UTF_32_LE;
перерыв;
}
еще
if ((bom [0] == (byte) 0x00) &&
(bom [1] == (byte) 0x00) &&
(bom [2] == (byte) 0xFE) &&
(bom [3] == (byte) 0xFF))
{
this.bom = BOM.UTF_32_BE;
перерыв;
}
случай 3:
if ((bom [0] == (byte) 0xEF) &&
(bom [1] == (byte) 0xBB) &&
(bom [2] == (byte) 0xBF))
{
this.bom = BOM.UTF_8;
перерыв;
}
случай 2:
if ((bom [0] == (byte) 0xFF) &&
(bom [1] == (byte) 0xFE))
{
this.bom = BOM.UTF_16_LE;
перерыв;
}
еще
if ((bom [0] == (byte) 0xFE) &&
(bom [1] == (byte) 0xFF))
{
this.bom = BOM.UTF_16_BE;
перерыв;
}
дефолт:
this.bom = BOM.NONE;
перерыв;
}
если (читать> 0)
in.unread (бом, 0, чтение);
}
/ **
* Возвращает
BOM
, который был обнаружен в упаковке
*
InputStream
объект.
*
* @ вернуть значение
BOM
.
* /
публичная финальная спецификация getBOM ()
{
// Тип спецификации неизменен.
вернуть бомбу;
}
/ **
* Пропускает
BOM
, который был найден в упаковке
*
InputStream
объект.
*
* @ вернуть это
UnicodeBOMInputStream
.
*
* @ выбрасывает IOException при попытке пропустить спецификацию из упакованного
*
InputStream
объект.
* /
публичная финальная синхронизированная UnicodeBOMInputStream skipBOM () выдает IOException
{
если (! пропущено)
{
in.skip (bom.bytes.length);
пропущено = верно;
}
верни это;
}
/ **
* {@inheritDoc}
* /
public int read () выбрасывает IOException
{
вернуть in.read ();
}
/ **
* {@inheritDoc}
* /
public int read (последний байт b []) выдает IOException,
Исключение нулевого указателя
{
вернуть in.read (b, 0, b.length);
}
/ **
* {@inheritDoc}
* /
public int read (последний байт b [],
окончательный int off,
final int len) выдает IOException,
Исключение нулевого указателя
{
вернуть in.read (b, off, len);
}
/ **
* {@inheritDoc}
* /
public long skip (final long n) выдает IOException
{
вернуть in.skip (n);
}
/ **
* {@inheritDoc}
* /
public int available () выдает IOException
{
вернуть in.available ();
}
/ **
* {@inheritDoc}
* /
public void close () выбрасывает IOException
{
in.close ();
}
/ **
* {@inheritDoc}
* /
общедоступный синхронизированный знак пустоты
{
in.mark (readlimit);
}
/ **
* {@inheritDoc}
* /
public синхронизированный void reset () выбрасывает IOException
{
in.reset ();
}
/ **
* {@inheritDoc}
* /
public boolean markSupported ()
{
return in.markSupported ();
}
закрытый финал PushbackInputStream in;
закрытый финал BOM bom;
приватный логический пропуск = false;
} // UnicodeBOMInputStream
И вы используете это так:
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStreamReader;
public final class UnicodeBOMInputStreamUsage
{
public static void main(final String[] args) throws Exception
{
FileInputStream fis = new FileInputStream("test/offending_bom.txt");
UnicodeBOMInputStream ubis = new UnicodeBOMInputStream(fis);
System.out.println("detected BOM: " + ubis.getBOM());
System.out.print("Reading the content of the file without skipping the BOM: ");
InputStreamReader isr = new InputStreamReader(ubis);
BufferedReader br = new BufferedReader(isr);
System.out.println(br.readLine());
br.close();
isr.close();
ubis.close();
fis.close();
fis = new FileInputStream("test/offending_bom.txt");
ubis = new UnicodeBOMInputStream(fis);
isr = new InputStreamReader(ubis);
br = new BufferedReader(isr);
ubis.skipBOM();
System.out.print("Reading the content of the file after skipping the BOM: ");
System.out.println(br.readLine());
br.close();
isr.close();
ubis.close();
fis.close();
}
} // UnicodeBOMInputStreamUsage