Estoy intentando leer archivos CSV usando Java. Algunos de los archivos pueden tener una marca de orden de bytes al principio, pero no todos. Cuando está presente, el orden de bytes se lee junto con el resto de la primera línea, lo que provoca problemas con las comparaciones de cadenas.
¿Existe una manera fácil de omitir la marca de orden de bytes cuando está presente?
¡Gracias!
Respuestas:
EDITAR : Hice una versión adecuada en GitHub: https://github.com/gpakosz/UnicodeBOMInputStream
Aquí hay una clase que codifiqué hace un tiempo, acabo de editar el nombre del paquete antes de pegarlo. Nada especial, es bastante similar a las soluciones publicadas en la base de datos de errores de SUN. Introdúzcalo en su código y estará bien.
Y lo estás usando de esta manera:
fuente
La biblioteca de IO de Apache Commons tiene una función
InputStream
que puede detectar y descartar listas de materiales:BOMInputStream
(javadoc) :Si también necesita detectar diferentes codificaciones, también puede distinguir entre varias marcas de orden de bytes diferentes, por ejemplo, UTF-8 vs UTF-16 big + little endian - detalles en el enlace del documento anterior. A continuación, puede utilizar el detectado
ByteOrderMark
para elegir unCharset
para decodificar la secuencia. (Probablemente haya una forma más simplificada de hacer esto si necesita toda esta funcionalidad, ¿tal vez el UnicodeReader en la respuesta de BalusC?). Tenga en cuenta que, en general, no hay una muy buena manera de detectar en qué codificación están algunos bytes, pero si el flujo comienza con una lista de materiales, aparentemente esto puede ser útil.Editar : si necesita detectar la lista de materiales en UTF-16, UTF-32, etc., entonces el constructor debería ser:
Upvote @ martin-charlesworth's comment :)
fuente
boolean
argumento para especificar si incluir o excluir la lista de materiales. Ejemplo:BOMInputStream bomIn = new BOMInputStream(in, false); // don't include the BOM
BOMInputStream bomIn = new BOMInputStream(is, ByteOrderMark.UTF_8, ByteOrderMark.UTF_16BE, ByteOrderMark.UTF_16LE, ByteOrderMark.UTF_32BE, ByteOrderMark.UTF_32LE);
BOMInputStream(InputStream delegate) Constructs a new BOM InputStream that excludes a ByteOrderMark.UTF_8 BOM.
Solución más simple:
Muestra de uso:
¡Funciona con las 5 codificaciones UTF!
fuente
La API de datos de Google tiene una
UnicodeReader
que detecta automáticamente la codificación.Puedes usarlo en lugar de
InputStreamReader
. Aquí hay un extracto, ligeramente compacto, de su fuente, que es bastante sencillo:fuente
(bom[0] == (byte) 0xFF) && (bom[1] == (byte) 0xFE) && (bom[2] == (byte) 0x00) && (bom[3] == (byte) 0x00)
que sea cierto, entonces el caso UTF-16LE ((bom[0] == (byte) 0xFF) && (bom[1] == (byte) 0xFE)
) ya habría coincidido.La
Apache Commons IO
Biblioteca BOMInputStream ya ha sido mencionado por @rescdsk, pero no verlo menciona cómo obtener unaInputStream
sin BOM el BOM.Así es como lo hice en Scala.
fuente
public BOMInputStream(InputStream delegate) { this(delegate, false, ByteOrderMark.UTF_8); }
. ExcluyeUTF-8 BOM
por defecto.Constructs a new BOM InputStream that excludes a ByteOrderMark.UTF_8 BOM.
Para eliminar simplemente los caracteres BOM de su archivo, recomiendo usar Apache Common IO
Establezca incluir en falso y se excluirán los caracteres de su lista de materiales.
fuente
Lamentablemente no. Tendrás que identificarte y saltarte. Esta página detalla lo que debe estar atento. Consulte también esta pregunta SO para obtener más detalles.
fuente
Tuve el mismo problema, y como no estaba leyendo en un montón de archivos, hice una solución más simple. Creo que mi codificación era UTF-8 porque cuando imprimí el carácter ofensivo con la ayuda de esta página: Obtener el valor Unicode de un carácter , encontré que lo era
\ufeff
. Usé el códigoSystem.out.println( "\\u" + Integer.toHexString(str.charAt(0) | 0x10000).substring(1) );
para imprimir el valor Unicode ofensivo.Una vez que tuve el valor Unicode ofensivo, lo reemplacé en la primera línea de mi archivo antes de continuar leyendo. La lógica empresarial de esa sección:
Esto solucionó mi problema. Luego pude seguir procesando el archivo sin problemas. Agregué que
trim()
solo en caso de espacios en blanco iniciales o finales, puede hacerlo o no, según sus necesidades específicas.fuente