(редактирование для уточнения и добавления кода)
Здравствуйте,
У нас есть требование проанализировать данные, отправленные пользователями по всему миру. Наши системы Linux имеют стандартную локаль en_US.UTF-8. Однако мы часто получаем файлы с диакритическими знаками в их именах, таких как "special_á_ã_è_characters.doc
". Хотя ОС прекрасно справляется с этими файлами, а strace показывает, что ОС передает правильное имя файла в программу Java, Java перенаправляет имена и бросает исключение "file not found", которое пытается открыть их.
Эта простая программа может проиллюстрировать проблему:
import java.io.*;
import java.text.*;
public class load_i18n
{
public static void main( String [] args ) {
File actual = new File(".");
for( File f : actual.listFiles()){
System.out.println( f.getName() );
}
}
}
Запуск этой программы в каталоге, содержащем файл special_á_ã_è_characters.doc
, и по умолчанию для английского языка по умолчанию:
special_�_�_�_characters.doc
Установка языка через экспорт LANG = es_ES @UTF-8 правильно выдает имя файла (но является неприемлемым решением, так как вся система теперь запущена на испанском языке.) Явное определение локали внутри программы, как показано ниже, не имеет эффекта или. Ниже я изменил программу: a) попытался открыть файл и b) распечатать имя как в ASCII, так и в виде байтового массива, когда он не может открыть файл:
import java.io.*;
import java.util.Locale;
import java.text.*;
public class load_i18n
{
public static void main( String [] args ) {
// Stream to read file
FileInputStream fin;
Locale locale = new Locale("es", "ES");
Locale.setDefault(locale);
File actual = new File(".");
System.out.println(Locale.getDefault());
for( File f : actual.listFiles()){
try {
fin = new FileInputStream (f.getName());
}
catch (IOException e){
System.err.println ("Can't open the file " + f.getName() + ". Printing as byte array.");
byte[] textArray = f.getName().getBytes();
for(byte b: textArray){
System.err.print(b + " ");
}
System.err.println();
System.exit(-1);
}
System.out.println( f.getName() );
}
}
}
Это приводит к выходу
es_ES
load_i18n.class
Can't open the file special_�_�_�_characters.doc. Printing as byte array.
115 112 101 99 105 97 108 95 -17 -65 -67 95 -17 -65 -67 95 -17 -65 -67 95 99 104 97 114 97 99 116 101 114 115 46 100 111 99
Это показывает, что проблема не просто проблема с отображением консоли, так как одни и те же символы и их представления выводятся в байтах или в формате ASCII. Фактически дисплей консоли работает даже при использовании LANG = en_US.UTF-8 для некоторых утилит, таких как bash echo:
[[email protected] tmp]$ echo $LANG
en_US.UTF-8
[[email protected] tmp]$ echo *
load_i18n.class special_á_ã_è_characters.doc
[[email protected] tmp]$ ls
load_i18n.class special_?_?_?_characters.doc
[[email protected] tmp]$
Можно ли изменить этот код таким образом, чтобы при запуске в Linux с LANG = en_US.UTF-8 он читал имя файла таким образом, чтобы его можно было успешно открыть?