Обычно я не задаю здесь вопросов, но проблемы, с которыми я сталкиваюсь, настолько велики ie, что я больше не могу бороться с ними в одиночку, я измотан. Во всяком случае, я собираюсь описать все, что я нашел, и я нашел много интересных вещей, в которые я хочу верить, поможет кто-то мне помочь.
Версии программного обеспечения: - ОС: Windows 10 Pro версия: 1909 сборка: 18363.720 - IntelliJ IDEA: 2019.2.4 Ultimate - версия Gradle-оболочки: 5.2.1-all - jdk: 8
Проблема лежит в кодировках, особенно в выводе консоли в проекте Gradle.
Вот мой файл build.gradle:
plugins {
id 'java'
id 'idea'
id 'application'
}
group 'com.diceeee.mentoring'
version 'release'
sourceCompatibility = 1.8
application.mainClassName('D')
compileJava.options.encoding = 'utf-8'
tasks.withType(JavaCompile) {
options.encoding = 'utf-8'
}
repositories {
mavenCentral()
jcenter()
}
dependencies {
testCompile group: 'junit', name: 'junit', version: '4.12'
}
Мои исходники находятся в кодировке UTF-8 с CRLF, поэтому в build.gradle я установил, что исходники должны быть скомпилированы с utf-8 кодировка вместо моей системы по умолчанию windows -1251 кодировка.
Вот D. java:
import java.io.FileWriter;
import java.io.IOException;
public class D {
public static void main(String[] args) throws IOException {
System.out.println(System.getProperty("file.encoding"));
String testLine = "Проверка работоспособности И Ш";
System.out.println(testLine);
FileWriter writer = new FileWriter("D:\\test.txt");
writer.write(testLine);
writer.close();
}
}
Также у меня есть gradle.properties с одной строкой:
org.gradle.jvmargs=-Dfile.encoding=utf-8
Я проверил, работает ли он, и убедился, что он работает, кодировка Encoder в System.out действительно изменилась на utf-8.
Когда я запускаю свой проект gradle, я получаю следующее:
21:04:53: Executing task 'D.main()'...
> Task :compileJava UP-TO-DATE
> Task :processResources NO-SOURCE
> Task :classes UP-TO-DATE
> Task :D.main()
UTF-8
�������� ����������������� � �
Deprecated Gradle features were used in this build, making it incompatible with Gradle 6.0.
Use '--warning-mode all' to show the individual deprecation warnings.
See https://docs.gradle.org/5.2.1/userguide/command_line_interface.html#sec:command_line_warnings
BUILD SUCCESSFUL in 0s
2 actionable tasks: 1 executed, 1 up-to-date
21:04:54: Task execution finished 'D.main()'.
Приходит больше информации. 1) Не случайно я оставил вывод в файле в коде. Если мы попытаемся просмотреть файл, мы увидим следующее:
Проверка работоспособности И Ш
Я не уверен, правильно ли это, но я пришел к выводу, что проблема лежит где-то в консоли, потому что, если будет проблема при кодировке по умолчанию средство записи файлов использовало неправильную кодировку для файла, и выходные данные были бы равны. Но этого не происходит.
2) Я отлаживал внутренние компоненты классов PrintStream, OutputStreamWriter и StreamEncoder. StreamEncoder действительно использует кодировку utf-8, а также кодирует текст utf-8 в правильную последовательность байтов: String testLine = "Проверка работоспособности И Ш"; Каждая буква кириллицы c составляет 2 байта, пробелы - 1 байт, если мы посчитаем все буквы, мы получим 57.
Теперь посмотрите здесь: Экран отладки кодировщика с результирующими байтами
Итак, как мы видим, мы получаем эти первые 57 байтов (остальные взяты из других входных данных, ограничения использования буфера):
[-48, -97, -47, -128, -48, -66, -48, -78, -48, -75, -47, -128, -48, -70, -48, -80, 32, -47, -128, -48, -80, -48, -79, -48, -66, -47, -126, -48, -66, -47, -127, -48, -65, -48, -66, -47, -127, -48, -66, -48, -79, -48, -67, -48, -66, -47, -127, -47, -126, -48, -72, 32, -48, -104, 32, -48, -88, 91]
выглядит правильно, буквы кириллицы c закодированы как [ -48, -97], [-47, -128] и другие группы по 2 байта, поэтому выглядит красиво, пробелы тоже совпадают. Итак, кодировщик делает большую работу, он работает, но что тогда происходит? Я не знаю. Шутки в сторону. Но есть больше информации. Если это не показалось ошеломляющим, я приготовил кое-что еще для вас.
Я создал чистый Java проект без каких-либо gradle / maven et c, только мой собственный jdk и ничего более. Программа такая же:
package com.company;
import java.io.FileWriter;
import java.io.IOException;
public class Main {
public static void main(String[] args) throws IOException {
System.out.println(System.getProperty("file.encoding"));
String testLine = "Проверка работоспособности И Ш";
System.out.println(testLine);
FileWriter writer = new FileWriter("D:\\test.txt");
writer.write(testLine);
writer.close();
}
}
Я ее запускаю и что я получу?
"C:\Program Files\Java\jdk1.8.0_181\bin\java.exe" "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2019.2.4\lib\idea_rt.jar=58901:C:\Program Files\JetBrains\IntelliJ IDEA 2019.2.4\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_181\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\rt.jar;C:\Users\<my_removed_name>\IdeaProjects\test\out\production\test" com.company.Main
UTF-8
Проверка работоспособности И Ш
Process finished with exit code 0
И после этого я просто умер. Wtf происходит ??? Вернемся к проекту gradle. Я сделал небольшую модификацию:
import java.io.FileWriter;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
public class D {
public static void main(String[] args) throws IOException {
System.out.println(System.getProperty("file.encoding"));
String testLine = new String("Проверка работоспособности И Ш".getBytes(StandardCharsets.UTF_8), "windows-1251");
System.out.println(testLine);
FileWriter writer = new FileWriter("D:\\test.txt");
writer.write(testLine);
writer.close();
}
}
И теперь вывод:
21:43:06: Executing task 'D.main()'...
> Task :compileJava
> Task :processResources NO-SOURCE
> Task :classes
> Task :D.main()
UTF-8
Проверка работоспособности �? Ш
Deprecated Gradle features were used in this build, making it incompatible with Gradle 6.0.
Use '--warning-mode all' to show the individual deprecation warnings.
See https://docs.gradle.org/5.2.1/userguide/command_line_interface.html#sec:command_line_warnings
BUILD SUCCESSFUL in 0s
2 actionable tasks: 2 executed
21:43:06: Task execution finished 'D.main()'.
В файле:
Проверка работоспособности � Ш
Кроме того, этот вывод в консоли является первым вещь, которая подтолкнула меня, чтобы определить, что идет не так, я просто кодировал и обнаружил, что что-то действительно не так с кириллицей c «И». Я пытался решить это, и снова, и снова ... и теперь я здесь, потому что я в тупике, я перепробовал все, что я нашел в аналогичных вопросах и темах о проблемах кодирования, у меня есть красный некоторые статьи о кодировке по умолчанию в java, о том, что Windows использует кодировку cp866 в консоли, кодировку windows -1251 по умолчанию, что нам нужно явно определить кодировку с -Dfile.encoding = UTF-8, ничего не помогает, я даже не знаю, что искать, чтобы найти проблему. Я думал, что gradle не распознает свойство, и кодировка по-прежнему windows -1251, но отладка показала, что я был не прав.
Итак, вот полный список вещей, которые я пытался решить: 1) Установить -Dfile.encoding = UTF-8 в файлах idea.exe.vmoptions и idea64.exe.vmtions с перезапуском. Не помогло 2) Установите UTF-8 в IntelliJ IDEA -> Настройки -> Редактор -> Кодировки файлов везде. Не помогло 3) Установите кодировку компилятора gradle в utf-8. Не помогло 4) Установите опцию gradle jvm org.gradle.jvmargs = -Dfile.encoding = utf-8. Не помогло 5) Проверено, что Windows имеет русский язык по умолчанию для программ, которые не поддерживают Unicode для поддержки кириллицы c. Не помогло.
Я не уверен, в чем проблема с gradle, потому что чистый проект без gradle работает отлично, вывод на консоль в порядке. Но с Gradle символы кириллицы c неверны. Кроме того, я попытался как-то исправить вывод на консоль с помощью getBytes (charset) и нового метода / конструктора String (byte [], charset), я попробовал следующие варианты:
String testLine = new String("Проверка работоспособности И Ш".getBytes(StandardCharsets.UTF_8), "windows-1251");
Output:
Проверка работоспособности �? Ш
Не работает.
String testLine = new String("Проверка работоспособности И Ш".getBytes(StandardCharsets.UTF_8), "cp866");
Output:
?�?�???????�???? ?�???????�???�?????�?????????�?�?? ?� ?�
Не работает.
String testLine = new String("Проверка работоспособности И Ш".getBytes(StandardCharsets.UTF_8), "utf-8");
Output:
�������� ����������������� � �
Результат, который мы получаем без каких-либо преобразований.
Кроме того, я попробовал еще одну вещь - обертку System.out для установки другой кодировки консоли.
public class D {
public static void main(String[] args) throws IOException {
System.out.println(System.getProperty("file.encoding"));
System.setOut(new PrintStream(System.out, true, "utf-8"));
String testLine = "Проверка работоспособности И Ш";
System.out.println(testLine);
FileWriter writer = new FileWriter("D:\\test.txt");
writer.write(testLine);
writer.close();
}
}
И у нас все еще ничего нет, даже не изменилось:
> Task :D.main()
UTF-8
�������� ����������������� � �
Ну, по всей этой информации, я думаю, что с консолью что-то не очень хорошо сам по себе, потому что даже при последнем выполнении приведенного выше кода этот вывод выводится в файле:
Проверка работоспособности И Ш
Это кодировка utf-8, это правильный вывод. Но System.out.println печатает что-то иррациональное в консоли, даже если Encoder работает хорошо. Я не знаю, что происходит (извините за грязные разговоры), если проблема действительно в градле, как это проверить? Или как позволить gradle использовать другую кодировку для вывода на консоль? Или, может быть, это все еще что-то с IntelliJ IDEA, даже если вывод в проекте без Gradle правильный?
Я чувствую себя детективом, но я застрял, застрял в этом случае. Я благодарен, если кто-нибудь мне поможет.