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 Integer
i, 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é.
Čo tak použiť Notepad++?? :) Je možné uložiť file s encoding UTF-8 without BOM
Samozrejme, ľubovoľný rozumný editor to dokáže. Celý problém u mňa vznikol na online kódení na prednáške, kde nebolo po ruke nič iné.