web-dev-qa-db-fra.com

Lecture UTF-8 - marqueur de nomenclature

Je lis un fichier via un FileReader - le fichier est décodé UTF-8 (avec BOM) maintenant mon problème est: j'ai lu le fichier et sorti une chaîne, mais malheureusement le marqueur BOM est également sorti. Pourquoi cela se produit-il?

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");
}

sortie après la première ligne

?<style>
60
onigunn

En Java, vous devez consommer manuellement la nomenclature UTF8 si elle est présente. Ce comportement est documenté dans la base de données Java, ici et ici . Il n'y aura pas de correctif pour l'instant car il cassera les outils existants comme les analyseurs JavaDoc ou XML. Le Apache IO Commons fournit un BOMInputStream pour gérer cette situation.

Jetez un œil à cette solution: Gérer le fichier UTF8 avec la nomenclature

70
RealHowTo

La solution la plus simple consiste probablement à supprimer le \uFEFF à partir de la chaîne, car il est extrêmement peu probable qu'elle apparaisse pour une autre raison.

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

Voir aussi ce rapport de bug sur la goyave

33
finnw

Utilisez la bibliothèque Apache Commons .

Classe: org.Apache.commons.io.input.BOMInputStream

Exemple d'utilisation:

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();
}
24
peenut

Voici comment j'utilise Apache BOMInputStream, il utilise un bloc try-with-resources. L'argument "false" indique à l'objet d'ignorer les nomenclatures suivantes (nous utilisons des fichiers texte "sans nomenclature" pour des raisons de sécurité, haha):

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)

}
6
snakedoctor

Utilisez Apache Commons IO .

Par exemple, jetons un œil à mon code (utilisé pour lire un fichier texte avec des caractères latins et cyrilliques) ci-dessous:

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

Par conséquent, nous avons une ArrayList nommée "ari" avec tous les caractères du fichier "1.txt" à l'exception de la nomenclature.

1
pawman

Considérez nicodeReader de Google qui fait tout ce travail pour vous.

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

Dépendance Maven:

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

Il est mentionné ici qu'il s'agit généralement d'un problème avec les fichiers sous Windows.

Une solution possible serait d'exécuter le fichier via un outil comme dos2unix en premier.

1
Drake Sobania

Le moyen le plus simple que j'ai trouvé pour contourner la nomenclature

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
David

Si quelqu'un veut le faire avec la norme, ce serait un moyen:

public static String cutBOM(String value) {
    // UTF-8 BOM is EF BB BF, see https://en.wikipedia.org/wiki/Byte_order_mark
    String bom = String.format("%x", new BigInteger(1, value.substring(0,3).getBytes()));
    if (bom.equals("efbbbf"))
        // UTF-8
        return value.substring(3, value.length());
    else if (bom.substring(0, 2).equals("feff") || bom.substring(0, 2).equals("ffe"))
        // UTF-16BE or UTF16-LE
        return value.substring(2, value.length());
    else
        return value;
}
0
Markus