Как я могу открыть файлы, содержащие диакритические знаки в Java?

(редактирующий для разъяснения и добавляющий некоторый код)

Привет, у Нас есть требование для парсинга данных, отправленных от пользователей во всем мире. Наши системы Linux имеют локаль по умолчанию en_US.UTF-8. Однако мы часто получаем файлы с диакритическими знаками на их имена такой как"special_á_ã_è_characters.doc". Хотя ОС может иметь дело с этими прекрасными файлами, и strace показывает ОС, передающую корректное имя файла программе Java, Java munges имена, и бросает "файл, не найденный" io исключение, пытающееся открыть их.

Эта простая программа может проиллюстрировать проблему:

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 распечатывает имя файла правильно (но недопустимое решение, так как вся система теперь работает на испанском языке.) Установка Explicitly Локаль в программе как следующее не имеет никакого эффекта также. Ниже я изменил программу для 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 для некоторых утилит как эхо удара:

[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, это читает имя файла таким способом, которым это может быть успешно открыто?

13
задан Mark Juric 21 June 2010 в 12:20
поделиться

2 ответа

Во-первых, используемая кодировка символов не связана напрямую с локалью. Так что смена локали не сильно поможет.

Во-вторых, � типично для символа замены Unicode U + FFFD , печатаемого в ISO-8859-1 вместо UTF-8. Вот свидетельство:

System.out.println(new String("�".getBytes("UTF-8"), "ISO-8859-1")); // �

Итак, есть две проблемы:

  1. Ваша JVM читает эти специальные символы как .
  2. Ваша консоль использует ISO-8859-1 для отображения символов.

Для Sun JVM аргумент VM -Dfile.encoding = UTF-8 должен исправить первую проблему. Вторую проблему нужно исправить в настройках консоли. Если вы используете, например, Eclipse, вы можете изменить его в Window> Preferences> General> Workspace> Text File Encoding . Установите также UTF-8.


Обновление : Согласно вашему обновлению:

byte[] textArray = f.getName().getBytes();

Это должно было быть следующее, чтобы исключить влияние кодировки платформы по умолчанию:

byte[] textArray = f.getName().getBytes("UTF-8");

Если это все еще отображается так же, значит проблема глубже. Какую именно JVM вы используете? Сделайте java -версию . Как было сказано ранее, аргумент -Dfile.encoding специфичен для Sun JVM. Некоторые машины Linux поставляются с GNU JVM или OpenJDK JVM, и тогда этот аргумент может не работать.

8
ответ дан 2 December 2019 в 00:17
поделиться

Системное свойство Java file.encoding должно соответствовать кодировке символов консоли. Это свойство должно быть установлено при запуске java в командной строке:

java -Dfile.encoding=UTF-8 …

Обычно это происходит автоматически, потому что кодировка консоли обычно является кодировкой платформы по умолчанию, и Java будет использовать кодировку платформы по умолчанию, если вы не Не указываю одно явно.

1
ответ дан 2 December 2019 в 00:17
поделиться
Другие вопросы по тегам:

Похожие вопросы: