Od “Integer nevie naparsovať jednotku” k “Java nepodporuje BOM v UTF-8”

Predstavme si jednoduchý zdrojový súbor:

1|Ežo
2|Estera
3|Eliáš
4|Žofka

A parser identifikátorov:

package sk.upjs.ics.utf8demo;

import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;

public class BadFileReader {

    public static void main(String[] args) throws FileNotFoundException {
        try(Scanner scanner = new Scanner(new File("mena.txt"))) {
            while (scanner.hasNextLine()) {
                String line = scanner.nextLine();
                String[] components = line.split("\\|");

                int id = Integer.parseInt(components[0]);
                System.out.println(id);
            }
        }
    }
}

V niektorých situáciách (a to poviem hneď, v ktorých) dostaneme v NetBeanse skvelú a hlavne W? T? F? hlášku:

Exception in thread "main" java.lang.NumberFormatException: For input string: "1"
    at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
    at java.lang.Integer.parseInt(Integer.java:492)
    at java.lang.Integer.parseInt(Integer.java:527)
    at sk.upjs.ics.utf8demo.BadFileReader.main(BadFileReader.java:15)

Ako to, že reťazec s jediným znakom 1 sa nedá naparsovať? Veď toto určite funguje bez chyby:

int id = Integer.parseInt("1");

Riešenie

Toto je presne prípad, keď výnimka absolútne nezodpovedá pôvodnému problému, a dokonca zavádza na nesprávnu cestu.

Problém totiž nie je v Integeri, ale v kódovaní UTF-8.

BOM saje

Stačí, aby bol dátový súbor uložený ako UTF-8 s BOM bajtami na začiatku, a máme zarobené na problém. O to viac, keď sme v Windowsovská konzola vypíše aspoň zmysluplnejšiu hlášku:

Exception in thread "main" java.lang.NumberFormatException: For input string: "´╗┐1"
        at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
        at java.lang.Integer.parseInt(Integer.java:492)
        at java.lang.Integer.parseInt(Integer.java:527)
        at sk.upjs.ics.utf8demo.BadFileReader.main(BadFileReader.java:16)   

Tri paznaky (´╗┐) korešpondujú s hexa zápisom EF BB BF BOM znakov.

V netbeansáckej konzole sa však o týchto znakoch nedozvieme (odskúšané na MacOS i na Windowse 8).

Čo to zapríčiňuje?

  • java.util.Scanner nepodporuje BOM. Vlastne celá Java má problém s BOMami, ktoré je nutné spracovať ručne. Chyba je dokumentovaná minimálne dvakrát. 4508058 a 6378911.

Čo z toho ešte vyplýva?

  • NetBeans vyrába nové súbory v štandardnom kódovaní UTF-8, a BOM sa samozrejme nepoužíva. Nastavenie je odvodené z nastavenia kódovania projektových zdrojákov, a to jednotne pre celý projekt. Zmeniť kódovanie pre jednotlivé súbory nie je možné.
  • Projekty spúšťané v rámci NetBeans bežia štandardne vždy s kódovaním UTF-8. Overiť to môžeme cez výpis systémovej property file encoding:

    System.out.println(System.getProperty("file.encoding"));
    

    To je rozdiel oproti kódovaniu samotného operačného systému, lebo..

  • … Eclipse spúšťa projekty s príslušným platformovým kódovaním: na Windowse napr. windows-1250.

    System.out.println(System.getProperty("file.encoding"));
    
  • Notepad ukladá UTF-8 dokumenty vrátane BOMu. Vypnúť BOM nie je možné.

2 thoughts on “Od “Integer nevie naparsovať jednotku” k “Java nepodporuje BOM v UTF-8”

Pridaj komentár

Vaša e-mailová adresa nebude zverejnená. Vyžadované polia sú označené *