Создание файлов UTF-8 в Java из работающего Jar - PullRequest
5 голосов
/ 13 июня 2010

У меня есть небольшой Java-проект, в котором я установил свойства файлов классов в UTF-8 (я использую много посторонних символов, которых нет в CP1252 по умолчанию).

Цель - создать текстовый файл (в Windows), содержащий список элементов. При запуске файлов классов из самого Eclipse (нажав Ctrl + F11) он без проблем создает файл и открывает его в другом редакторе (я использую Notepad ++). Я вижу символы так, как хотел.

┌──────────────────────────────────────────────────┐
│                          Universidade2010 (18/18)│
│                                         hidden: 0│
├──────────────────────────────────────────────────┤

Но, когда я экспортирую проект (используя Eclipse) в качестве исполняемого файла Jar и запускаю его, используя 'javaw -jar project.jar', новый созданный файл представляет собой беспорядок знаков вопроса

????????????????????????????????????????????????????
?                          Universidade2010 (19/19)?
?                                         hidden: 0?
????????????????????????????????????????????????????

Я следовал нескольким советам о том, как использовать UTF-8 (который, по-видимому, по умолчанию не работает в Java), чтобы попытаться исправить это, поэтому теперь я использую

Writer w = new OutputStreamWriter(fos, "UTF-8");

и запись заголовка спецификации в файл, как в этом вопросе, на который уже дан ответ , но все еще безуспешно при экспорте в Jar

Мне не хватает какого-либо свойства или команды командной строки, поэтому Java знает, что я хочу создать файлы UTF-8 по умолчанию?


проблема не в создании самого файла, потому что при разработке файл выводится корректно (с символами юникода)

Класс, который создает файл, теперь (и после предложения использовать класс Charset) выглядит так:

public class Printer {

    File f;
    FileOutputStream fos;
    Writer w;
    final byte[] utf8_bom = { (byte) 0xEF, (byte) 0xBB, (byte) 0xBF };

    public Printer(String filename){
        f = new File(filename);
        try {
            fos = new FileOutputStream(f);
            w = new OutputStreamWriter(fos, Charset.forName("UTF-8"));
            fos.write(utf8_bom);
        } catch (FileNotFoundException e) {
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void print(String s) {
        if(fos != null){
            try {
                fos.write(s.getBytes());
                fos.flush();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }

}

И все используемые символы определены так:

private final char pipe = '\u2502';         /* │ */
private final char line = '\u2500';         /* ─ */
private final char pipeleft = '\u251c';     /* ├ */
private final char piperight = '\u2524';    /* ┤ */
private final char cupleft = '\u250c';      /* ┌ */
private final char cupright = '\u2510';     /* ┐ */
private final char cdownleft = '\u2514';    /* └ */
private final char cdownright = '\u2518';   /* ┘ */

Проблема остается: при выводе в файл, просто запустив проект на Eclipse, файл получается идеальным, но после развертывания проекта на Jar и запуска его в выходном файле уничтожается форматирование (я выяснил, что они заменяются символом '?')

Я пришел к выводу, что это не проблема с кодом, это проблема развертывания его в файл Jar, я думаю, что Eclipse компилирует исходные файлы в CP1252 или что-то подобное, но даже заменяет все символы Юникода их кодовые константы не помогли

1 Ответ

6 голосов
/ 14 июня 2010

Я следовал нескольким советам о том, как использовать UTF-8 (который, по-видимому, по умолчанию не работает в Java)

По историческим причинам в кодировке Java по умолчанию используется системная кодировка (то, что больше имело смысл в Windows 95). Такое поведение вряд ли изменится. Насколько я знаю, в реализации кодировщика Java нет ничего плохого.

  private static final String BOM = "\ufeff";

  public static void main(String[] args) throws IOException {
    String data = "\u250c\u2500\u2500\u2510\r\n\u251c\u2500\u2500\u2524";
    OutputStream out = new FileOutputStream("data.txt");
    Closeable resource = out;
    try {
      Writer writer = new OutputStreamWriter(out, Charset.forName("UTF-8"));
      resource = writer;
      writer.write(BOM);
      writer.write(data);
    } finally {
      resource.close();
    }
  }

Приведенный выше код выдаст следующий текст с префиксом метки порядка байтов:

& # x250c; & # x2500; & # x2500; & # x2510;
& # X251c; & # X2500; & # X2500; & # x2524;

Приложения для Windows, такие как Блокнот, могут определять кодировку из спецификации и правильно декодировать файл.

Без кода невозможно обнаружить ошибки.

Мне не хватает какого-либо свойства или команды командной строки, поэтому Java знает, что я хочу создать файлы UTF-8 по умолчанию?

Нет - такой настройки нет. Некоторые могут предложить установить file.encoding в командной строке, но это плохая идея .


Я написал более полный пост в блоге на эту тему здесь .


Это переделка вашего кода :

public class Printer implements Closeable {
  private PrintWriter pw;
  private boolean error;

  public Printer(String name) {
    try {
      pw = new PrintWriter(name, "UTF-8");
      pw.print('\uFEFF'); // BOM
      error = false;
    } catch (IOException e) {
      error = true;
    }
  }

  public void print(String s) {
    if (pw == null) return;
    pw.print(s);
    pw.flush();
  }

  public boolean checkError() { return error || pw.checkError(); }

  @Override public void close() { if (pw != null) pw.close(); }
}

Большая часть нужных вам функций уже существует в PrintWriter. Обратите внимание, что вы должны предоставить некоторый механизм для проверки основных ошибок и закрытия потока (или вы рискуете пропустить файловые дескрипторы).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...