2012-03-16 68 views
21

Necesito sugerencias sobre cómo eliminar la lista de materiales de un archivo UTF-8 y crear una copia del resto del archivo xml.Cómo quitar la BOM de un archivo XML en Java

+1

los downvotes no son causa de un duplicado, que están ya a esta pregunta es demasiado amplia en la naturaleza: stackoverflow es para ayudar con problemas de programación específicos y localizados. Podemos ayudarlo a depurar un programa, no escribiremos uno para usted. –

+0

Estoy esperando que esto esté en -5 antes de responder;) – TacticalCoder

+0

@hari: ¿cuál es la codificación de su archivo? UTF-8? – TacticalCoder

Respuesta

32

Tener una herramienta de ruptura debido a una lista de materiales en un archivo UTF-8 es una cosa muy muy en mi experiencia. No sé por qué hubo tantos votos negativos (pero luego me da la oportunidad de intentar obtener suficiente voto para ganar una insignia SO especial;)

Más en serio: una BOM UTF-8 no suele ser suficiente ese sentido mucho pero es completamente válido (aunque desaconsejado) por las especificaciones. Ahora el problema es que mucha gente no sabe que una BOM es válida en UTF-8 y, por lo tanto, escribió herramientas/API rotas que no procesan correctamente estos archivos.

Ahora puede tener dos problemas diferentes: puede que quiera procesar el archivo desde Java o necesita usar Java para crear/arreglar mediante programación archivos que necesitan otras herramientas (rotas).

He tenido el caso en un concierto de consultoría donde el servicio de ayuda seguiría recibiendo mensajes de los usuarios que tenían problemas con algún editor de texto que arruinaría archivos UTF-8 perfectamente válidos producidos por Java. Así que tuve que solucionar ese problema asegurándome de eliminar la lista de materiales de cada archivo UTF-8 con el que estábamos tratando.

I desea eliminar una lista de materiales de un archivo, puede crear un nuevo archivo y omitir los primeros tres bytes. Por ejemplo:

... $ file /tmp/src.txt 
/tmp/src.txt: UTF-8 Unicode (with BOM) English text 

... $ ls -l /tmp/src.txt 
-rw-rw-r-- 1 tact tact 1733 2012-03-16 14:29 /tmp/src.txt 

... $ hexdump -C /tmp/src.txt | head -n 1 
00000000 ef bb bf 50 6f 6b 65 ... 

Como se puede ver, el archivo comienza con "EF BB BF", este es el (totalmente válido) BOM UTF-8.

Aquí es un método que toma un archivo y hace una copia de la misma por saltarse los tres primeros bytes:

public static void workAroundbrokenToolsAndAPIs(File sourceFile, File destFile) throws IOException { 
    if(!destFile.exists()) { 
     destFile.createNewFile(); 
    } 

    FileChannel source = null; 
    FileChannel destination = null; 

    try { 
     source = new FileInputStream(sourceFile).getChannel(); 
     source.position(3); 
     destination = new FileOutputStream(destFile).getChannel(); 
     destination.transferFrom(source, 0, source.size() - 3); 
    } 
    finally { 
     if(source != null) { 
      source.close(); 
     } 
     if(destination != null) { 
      destination.close(); 
     } 
    } 
} 

Tenga en cuenta que se trata de "prima": normalmente se querría hacer primero asegurarse de que tiene una BOM antes de llamar a esto o "Bad Thinks May Happen" [TM].

Puede revisar el archivo después:

... $ file /tmp/dst.txt 
/tmp/dst.txt: UTF-8 Unicode English text 

... $ ls -l /tmp/dst.txt 
-rw-rw-r-- 1 tact tact 1730 2012-03-16 14:41 /tmp/dst.txt 

... $ hexdump -C /tmp/dst.txt 
00000000 50 6f 6b 65 ... 

Y la lista de materiales se ha ido ...

Ahora si simplemente desea eliminar de forma transparente la lista de materiales para un roto su API de Java, entonces podría utilizar el pushbackInputStream se describe aquí: why org.apache.xerces.parsers.SAXParser does not skip BOM in utf8 encoded xml?

private static InputStream checkForUtf8BOMAndDiscardIfAny(InputStream inputStream) throws IOException { 
    PushbackInputStream pushbackInputStream = new PushbackInputStream(new BufferedInputStream(inputStream), 3); 
    byte[] bom = new byte[3]; 
    if (pushbackInputStream.read(bom) != -1) { 
     if (!(bom[0] == (byte) 0xEF && bom[1] == (byte) 0xBB && bom[2] == (byte) 0xBF)) { 
      pushbackInputStream.unread(bom); 
     } 
    } 
    return pushbackInputStream; } 

Tenga en cuenta que esto funciona, pero se defin itely NOT soluciona el problema más serio donde puede tener otras herramientas en la cadena de trabajo que no funcionen correctamente con los archivos UTF-8 que tienen una lista de materiales.

Y aquí hay un enlace a una pregunta con una respuesta más completa, que abarca otras codificaciones así:

Byte order mark screws up file reading in Java

+0

Votos no son un juicio sobre el * tema * de una pregunta, son un juicio sobre la * calidad * de una pregunta. Mira la información sobre herramientas para los botones de votación. – skaffman

+1

@skaffman: OK, pero en lugar de votar negativamente, pregunté si OP estaba usando un archivo UTF-8 (que sospechaba que era demasiado común) y luego lo agregué a la pregunta (y edité las etiquetas). No sé qué más se puede decir: * "¿Cómo eliminar una lista de materiales de un archivo?" * Es bastante autoexplicativo. Agregué "UTF-8". Por supuesto, hubiera sido más fácil para mí simplemente rechazarlo;) – TacticalCoder

+0

@TacticalCoder muchas gracias por sus sugerencias ... Estoy seguro de que esto resolvería el problema que tenía. – hari

Cuestiones relacionadas