Java options file encoding

Java options file encoding

В прошлой публикации мы установили и настроили Sublime Text в качестве редактора для написания кода на Java.

  • о компиляции и запуске Java-программ из консоли
  • как выводить в нее корректный русский текст
  • способ отображения байт-кода

На первых порах начинающему программисту очень важно научиться выполнять необходимые действия минимальными средствами, чтобы:

  • иметь представление, что происходит «под капотом»
  • не быть зависимым от среды разработки
  • не превратиться в специалиста по нажиманию кнопок в инструментах для профессионалов
  • не оказаться беспомощным за их пределами

Вам сейчас нужно максимально набить шишек, находясь в спартанских условиях, которые закалят и научат самостоятельно и оперативно решать возникающие проблемы. Это придаст уверенности и повысит вашу экспертность.

Есть такое понятие — профессиональный кругозор. Он важен для людей любой профессии. Программисты — не исключение. Если человек хочет стать настоящим разработчиком, обладающим фундаментальными знаниями, а не поверхностными и неструктурированными, то ему нужно изучать возможности языка последовательно и системно. Компиляция и запуск — это основа основ, это база, мимо которой никак нельзя пройти.

Компилировать и запускать программы на первых порах мы будем из консоли. В этой и последующих статьях мы будем много работать с этим инструментом. Это важный навык, который используется программистами повсеместно.

Откроем в Sublime Text терминал, нажав Ctrl + Alt + T (при этом файл MyFirstApp.java должен быть открыт в редакторе). Обязательно проверьте, что терминал запустился в папке StartJava (или где вы сохранили класс).

Для компиляции воспользуемся уже знакомой утилитой javac (java compiler, компилятор java). Она нужна для преобразования Java-кода в язык виртуальной машины (байт-код).

Читайте также:  Создать телеграм бот java

Отсутствие каких-либо сообщений свидетельствует о том, что компилятор не нашел ошибок в нашем коде. Результатом его работы стал файл MyFirstApp.class.

Как мы уже знаем, MyFirstApp.class содержит байт-код. Для его исполнения воспользуемся утилитой java. Именно она стартует JVM, которая, в свою очередь, запустит класс MyFirstApp.

Обратите внимание, что необходимо указать не имя файла MyFirstApp.class, а имя класса. При этом писать какое-либо расширение не нужно. Утилита java принимает в качестве параметра именно имя класса, а не имя файла, где он находится.

Мы уже не первый раз упоминаем про байт-код, но до сих пор в глаза его не видели. Исправим эту ситуацию.

Для отображения (декомпиляции) байт-кода класса необходимо в консоли написать команду javap -c MyFirstApp:

Как правило, умение читать и понимать байт-код, вносить в него изменения для рядовых Java-разработчиков обычно не требуется — это очень специфические знания. Так что долго не сидите на этой теме.

Если обобщить все этапы, которые проходит программа перед запуском, то схематично их можно отобразить в виде схемы:

Чтобы посмотреть, как работает программа, необходимо выполнить два действия: компиляцию и запуск. Если эти шаги требуется исполнять часто, то данный процесс рано или поздно надоест. Хотелось бы его упростить.

Удалите из папки class-файл, чтобы все было честно. И запустите программу без компиляции в явном виде, написав java MyFirstApp.java:

Мы только что запустили (и скомпилировали) файл с java-кодом без использования команды javac. При этом исходный код, в любом случае, компилируется в памяти (без создания на диске class-файла), а затем исполняется JVM.

Эта функция ограничена кодом, который хранится в одном файле. Она не сработает для программ, состоящих из двух и более файлов.

Теперь, когда вы умеете компилировать и запускать программу, можете поэкспериментировать с кодом MyFirstApp.java, внося в него изменения. Попробуем удалить точку с запятой.

 > java MyFirstApp.java error: 'main' method is not declared 'public static' 

Если вы используете Linux или macOS, то дальше можете не читать, т. к. ниже описаны проблемы и их решения для Windows. У вас таких проблем не будет!

Написанная нами программа выводит текст в консоли на английском языке. Как вы думаете, что произойдет, если попробовать вывести текст на русском?

 > java MyFirstApp.java Р?апиС?Р°Р?Р? Р?Р?Р?Р°Р?Р?С?, С?Р°Р?Р?С?Р°Р?С? Р?Р?Р·Р?Р? 

Что-то пошло не так и вместо русского текста отобразились какие-то закорючки. В чем тут причина и как эту ситуацию можно исправить?

Первое, что приходит в голову — это какая-то проблема с кодировкой. Нужно разобраться, в какой момент она возникает.

Посмотрим, какая кодировка у файла с нашим кодом. Она отображается в правом нижнем углу окна. Видим, что это UTF-8.

А какая кодировка используется в OC? Определить это можно разными путями. Например, в Windows в реестре (для его запуска из консоли используйте команду regedit) по следующему адресу HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Nls\CodePage можно посмотреть, чему равен параметр под названием ACP (ANSI code page).

У меня он имеет значение 1251. Это стандартная кодировка для русских версий Windows. У вас она может быть другой — все зависит от языка (кодировки) системы.

Есть еще один способ узнать кодировку, который подходит для любой ОС — это воспользоваться Java, поместив в наш класс две новых строки:

 import java.nio.charset.Charset; public class MyFirstApp < public static void main(String[] args) < System.out.println(Charset.defaultCharset().displayName()); >> 

Вникать в то, что означает этот код мы не будем — наша задача лишь получить универсальным способом значение кодировки. Но если в двух словах, то в первой строке мы подключаем класс Charset, а в пятой выводим на экран значение кодировки по умолчанию для ОС, воспользовавшись возможностями данного класса.

 > java MyFirstApp.java windows-1251 
 > chcp Текущая кодовая страница: 866 

Она выдала 866. Это же число можно наблюдать и в реестре у параметра OEMCP (Original equipment manufacturer code page). Это DOS-кодировка, которая досталась нам в наследство.

Не удивительно, что Java не смогла корректно отобразить кириллический текст, когда используется столько кодировок в одной ОС.

Дело в том, что во время компиляции компилятор определяет кодировку исходного кода, опираясь на значение кодировки по умолчанию (на кодировку вашей ОС), а не на кодировку файла. В разных системах используются разные кодировки по умолчанию: в Windows — windows-1251, в Linux и Mac — UTF-8.

В Windows, ко всему прочему, еще и кодировка консоли не совпадает с кодировкой системы! Консоль по историческим причинам имеет кодировку Cp866 (видимо, в целях совместимости).

Затем JVM определяет кодировку по умолчанию во время запуска, используя системное свойство file.encoding. Значение для этого свойства устанавливается Java-машиной один раз при старте на основании данных, взятых из ОС.

Кодировка, используемая при выводе в консоль тоже системная, а не консоли. Если они не совпадают, то не видать нам корректного вывода кириллицы.

В итоге кодировку надо учитывать во время компиляции, во время запуска и во время вывода текста на консоль, например, при вводе с клавиатуры. Невыполнение этого правила в любом из этих мест способно вызвать проблемы.

У компилятора есть опция -encoding. Она позволяет принудительно указать кодировку исходника, чтобы компилятор не определял ее, опираясь на кодировку системы. Как вы помните, файл имеет кодировку UTF-8. Вот ее мы и укажем: javac -encoding utf8 MyFirstApp.java.

Если для однофайловых программы вы решили не использовать явно компиляцию, а сразу писать java, то для переопределения системного свойства file.encoding существует специальная команда. Вместе с ней запуск программы будет выглядеть так:

 > java -Dfile.encoding=UTF8 MyFirstApp.java Написано однажды, работает везде 

-Dfile.encoding — это уже параметр JVM, с помощью которого мы устанавливаем принудительно нужное нам значение, сохраняя его в file.encoding.

От всех этих параметров и правил может закружиться голова. И все эти годы Java-разработчики жили и мучились с кодировками и ошибками, которые они вызывали в программах.

Но не прошло и 25 лет, как появилась хорошая новость. Начиная с Java 18, значение кодировки по умолчанию определяется не исходя из кодировки ОС, а исходя из того, что она является UTF-8 — отныне это кодировка по умолчанию. Никакие параметры больше не нужны. Убедимся в этом:

 > "C:\Program Files\java\SapMachine-18\bin\java.exe" MyFirstApp.java Написано однажды, работает везде > "C:\Program Files\java\SapMachine-18\bin\javac.exe" MyFirstApp.java > "C:\Program Files\java\SapMachine-18\bin\java.exe" MyFirstApp Написано однажды, работает везде 

Для тех, кто использует Java меньше 18, придется использовать все параметры, указанные ранее — ни куда от них не деться. Но и тут есть выход.

Утомительно все время указывать кодировку. Этот вопрос можно решить, используя JAVA_TOOL_OPTIONS со значением -Dfile.encoding=UTF8. Необходимо установить эту переменную и ее значение в качестве переменной среды (ранее мы уже имели дело с другой переменной — JAVA_HOME). Не забудьте перезапустить консоль.

Благодаря этой переменной кодировка будет устанавливаться автоматически при каждом запуске JVM. При этом в консоли будет отображаться сообщение:

 Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF8 
 > java MyFirstApp.java Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF8 Написано однажды, работает везде > javac MyFirstApp.java Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF8 > java MyFirstApp Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF8 Написано однажды, работает везде 

Забежим немного вперед и рассмотрим ситуацию, когда нам нужно ввести с клавиатуры что-то на русском языке. Да, ввод мы еще не проходили, но мне совсем не хочется размазывать эту информацию по разным статьям. Пусть все, что связано с компиляцией и запуском, с кодировками, их проблемы и решения будет в одном месте.

Добавим в наш код библиотечный класс Scanner, который позволит считывать, введенные с клавиатуры символы, и пару строк с его использованием:

 import java.util.Scanner; public class MyFirstApp < public static void main(String[] args) < System.out.println("Написано однажды, работает везде"); Scanner console = new Scanner(System.in); System.out.print("Введите свое имя: "); System.out.println(console.nextLine()); >> 
 > java MyFirstApp.java Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF8 Написано однажды, работает везде Введите свое имя: Максим . 
 замените Scanner console = new Scanner(System.in); на Scanner console = new Scanner(System.in, "cp866"); 
 > java MyFirstApp.java Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF8 Написано однажды, работает везде Введите свое имя: МАКСИМ ШШШШ ИИИИ МАКСИМ ШШШШ ИИИИ 

Если после всего проделанного, что я описал выше, у вас вместо русского текста выводится пустая строка, то необходимо в консоли ввести chcp 866 и заново запустить программу.

В этой статье мы научились компилировать и запускать java-программы, нашли способ побороть проблему с выводом кириллических символов в консоль, а также лучше стали понимать, как работают все эти механизмы.

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

Источник

UTF8 filenames with Java

Functions from java.io solely depend on the locale settings of your operating system. If you want to create the directory /tmp/foö/bär, save this snippet to a file called javaapplication1/JavaApplication1.java:

package javaapplication1; public class JavaApplication1 < static < System.setProperty("file.encoding", "UTF-8"); System.setProperty("sun.jnu.encoding", "UTF-8"); >public static void main(String[] args) < new java.io.File("/tmp/foö/bär").mkdirs(); >>
$ javac -encoding UTF-8 javaapplication/JavaApplication1.java
$ java -Dfile.encoding=UTF-8 -Dsun.jnu.encoding=UTF-8 javaapplication.JavaApplication1

If your environment is set to ASCII or not set at all, you will get /tmp/fo?/b?r. If your environment is set to ISO-8859-1 instead, you will get /tmp/fo\366/b\344r. System properties given on the commandline and in the static initialization block have no effect. You have to set your environment to an *.utf-8 locale:

$ LC_ALL=de_DE.utf-8 java javaapplication.JavaApplication1

Now you have a directory tree named /tmp/f\303\266/b\303\244r, which is the correct byte level encoding for UTF-8.

Using java.nio.*

In contrast to java.io, java.nio honors the sun.jnu.encoding system property set in the static initialization block:

package javaapplication1; public class JavaApplication1 < static < System.setProperty("sun.jnu.encoding", "UTF-8"); >public static void main(String[] args) throws java.io.IOException < java.nio.file.Files.createDirectories(java.nio.file.Paths.get("/tmp/foö/bär")); >>
$ javac -encoding UTF-8 javaapplication/JavaApplication1.java

But, you can omit any locale settings and system properties on the command line, and will still get directories with UTF-8 names:

$ java javaapplication.JavaApplication1
package javaapplication1; public class JavaApplication1 < public static void main(String[] args) throws java.io.IOException < java.nio.file.Files.createDirectories(java.nio.file.Paths.get("/tmp/foö/bär")); >>
$ LC_ALL=de_DE.utf-8 java javaapplication.JavaApplication1

Btw, java.nio just defines static functions plus several interfaces. For an object oriented language I find this highly unclean.

Источник

Оцените статью