( редактирование для уточнения и добавление некоторого кода )
Здравствуйте,
У нас есть требование для анализа данных, отправленных пользователями по всему миру. Наши системы Linux имеют стандартную локализацию en_US.UTF-8. Тем не менее, мы часто получаем файлы с диакритическими знаками в именах, таких как «special_á_ã_è_characters.doc
». Хотя ОС прекрасно справляется с этими файлами, и строка показывает, что ОС передает правильное имя файла программе Java, Java обрабатывает имена и создает исключение «файл не найден», пытаясь открыть их.
Эта простая программа может проиллюстрировать проблему:
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 правильно печатает имя файла (но это неприемлемое решение, поскольку вся система теперь работает на испанском языке.) Явная установка языкового стандарта внутри программы, как показано ниже, не имеет никакого эффекта или. Ниже я изменил программу, чтобы: а) попытаться открыть файл и б) распечатать имя как в 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's echo:
[mjuric@arrhchadm30 tmp]$ echo $LANG
en_US.UTF-8
[mjuric@arrhchadm30 tmp]$ echo *
load_i18n.class special_á_ã_è_characters.doc
[mjuric@arrhchadm30 tmp]$ ls
load_i18n.class special_?_?_?_characters.doc
[mjuric@arrhchadm30 tmp]$
Можно ли изменить этот код таким образом, чтобы при запуске под Linux с LANG = en_US.UTF-8 он считывал имя файла таким образом, чтобы его можно было успешно открыть?