2011-02-04 31 views
51

Estoy leyendo un archivo a través de un FileReader - el archivo está decodificado UTF-8 (con BOM) ahora mi problema es: leí el archivo y saqué una cadena, pero lamentablemente el marcador BOM se saca también ¿Por qué ocurre esto?Lectura UTF-8 - marcador 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"); 
} 

de salida después de la primera línea de

?<style> 
+3

no se supone UTF-8 para tener una lista de materiales! No es necesario ** ni recomendado ** por The Unicode Standard. – tchrist

+19

@tchrist: en Microsoft, no les importan los estándares. –

+1

Para ampliar el punto de Matti, todos los editores de texto MS prefijos de documentos UTF-8 con una lista de materiales. – Ant

Respuesta

60

En Java, debe consumir manualmente la BOM UTF8 si está presente. Este comportamiento está documentado en la base de datos de errores de Java, here y here. No habrá una solución por ahora porque romperá las herramientas existentes como los analizadores JavaDoc o XML. El Apache IO Commons proporciona un BOMInputStream para manejar esta situación.

Tome un vistazo a esta solución: Handle UTF8 file with BOM

+2

+1 para señalar Apache IO Commons BOMInputStream. – ArtB

-2

No está seguro de lo que se cree que está logrando con tmp.getBytes() y "UTF-8", etc.

estoy bastante Seguro que Java no admite listas de materiales, aunque no puedo encontrar la documentación que dice eso ahora.

También vale la pena señalar que BOMs in UTF-8 are meaningless, ya que la norma especifica el orden de bytes independientemente del hardware. Entonces, si puedes evitar que se generen en primer lugar, eso podría ayudar.

+0

Ayuda un poco decidir que el archivo/secuencia es UTF-8 y no UTF-16 o cualquier otra cosa. –

+1

No lo creo. Ciertamente no ayudará a distinguir de un archivo ISO-8859-x. – dty

+0

@ Paŭlo: las buenas estadísticas son más efectivas para detectar codificaciones. – ceztko

29

La solución más sencilla es probablemente sólo para eliminar el \uFEFF resultante de la cadena, ya que es muy poco probable que aparezca por cualquier otra razón.

tmp = tmp.replace("\uFEFF", ""); 

Véase también this Guava bug report

+0

Me salvó el día, gracias. –

+0

Intenté esto y funcionó muy bien. ¡Gracias! – Ricardo

+3

Lo malo de "extremadamente improbable" es que aparece muy raramente, por lo que localizar el error es extremadamente difícil ... :) Así que sea extremadamente cauteloso al usar este código si cree que su software será exitoso y duradero. , porque tarde o temprano cualquier situación existente ocurrirá. –

19

Uso del Apache Commons library.

Clase: El uso de org.apache.commons.io.input.BOMInputStream

Ejemplo:

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(); 
} 
+0

http://commons.apache.org/proper/commons-io/apidocs/org/apache/commons/io/input/BOMInputStream.html – bmoc

+0

Este código solo funcionará con la detección de BOM UTF-8 y excluyendo. comprobar la aplicación de bOMInputStream: '' ' /** * Construye un nuevo InputStream lista de materiales que detecta un * a {@ link ByteOrderMark # UTF_8} e incluye opcionalmente ella. * @param delegado InputStream delegar en * @param incluir cierto para incluir la lista de materiales UTF-8 o * falsa para excluirlo */ BOMInputStream pública (delegado InputStream, booleano incluye) { este (delegado, incluirá , ByteOrderMark.UTF_8); } '' ' – czupe

5

Así es como yo uso el BOMInputStream Apache, utiliza un bloque try-con-recursos. El argumento de la "falsa" dice al objeto de ignorar las siguientes listas de materiales (usamos archivos de texto "BOM-menos" por razones de seguridad, jaja):

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) 

} 
+0

nunca se puede averiguar cómo publicar cosas en este sitio - siempre termina AFU. – snakedoctor

0

Entonces se me ocurrió con este lector subclase

/* 
* 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(); 
    } 
} 
1

Se menciona here que esto suele ser un problema con los archivos en Windows.

Una posible solución sería ejecutar el archivo primero a través de una herramienta como dos2unix.

+0

sí, 'dos2unix' (que es parte de cygwin) tiene opciones para agregar (' --add-bom') y eliminar ('--remove-bom') bom. – Roman

0

Use Apache Commons IO.

Por ejemplo, vamos a echar un vistazo en mi código (utilizado para leer un archivo de texto con los dos caracteres latinos y cirílicos) a continuación:

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(); 

Como resultado hemos un ArrayList llamado "ari" con todo caracteres del archivo "1.txt" excepto BOM.

0

La manera más fácil que he encontrado para eludir 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("",""); 
0

Considere UnicodeReader de Google, que hace todo este trabajo para usted.

Charset utf8 = Charset.forName("UTF-8"); // default if no BOM present 
try (Reader r = new UnicodeReader(new FileInputStream(file), utf8)) { 
    .... 
} 

Maven Dependencia:

<dependency> 
    <groupId>com.google.gdata</groupId> 
    <artifactId>core</artifactId> 
    <version>1.47.1</version> 
</dependency>