【问题标题】:IntelliJ IDEA encoding problems in Gradle projectGradle 项目中的 IntelliJ IDEA 编码问题
【发布时间】:2020-07-05 09:18:52
【问题描述】:

平时,我不会在这里提问,但我所面对的问题是如此诡异,以至于我不能再独自一人解决它了,我已经筋疲力尽了。无论如何,我将描述我发现的所有东西,并且我发现了许多有趣的东西,我想相信它们会帮助别人帮助我。

软件版本: - 操作系统:Windows 10 专业版: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'
}

我的源代码是带有 CRLF 的 UTF-8 编码,所以在 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

我检查了它是否有效,并向自己保证它有效,System.out 中的 Encoder 编码确实更改为 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 = "Проверка работоспособности И Ш"; 每个西里尔字母为 2 个字节,空格为 1 个字节,如果我们计算所有字母,我们得到 57。

现在,看这里: Encoder debugging screen with resulting bytes

所以,正如我们所见,我们得到了前 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]

看起来不错,西里尔字母编码为 [-48, -97], [-47, -128] 和其他 2 字节组,所以看起来不错,空格也匹配。所以,编码器做得很好,它可以工作,但是发生了什么? 我不知道。严重地。但还有更多信息。如果它看起来并不令人兴奋,我已经为你准备了其他东西。

我创建了一个干净的 Java 项目,没有任何 gradle/maven 等,只有我自己的 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

在那之后,我就死了。发生了什么事???一会儿回到 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()'.

在文件中:

Проверка работоспособности � Ш

此外,控制台中的这个输出是促使我确定出了什么问题的第一件事,我只是在编码,发现西里尔字母“И”确实有问题。我试图解决它,一次又一次......现在我在这里,因为我处于死胡同,我尝试了我在关于编码问题的类似问题和主题中找到的所有内容,我有红色一些关于java中默认编码的文章,Windows在控制台中使用cp866编码,默认为windows-1251编码,我们需要使用-Dfile.encoding=UTF-8显式确定编码,没有任何帮助,我什至不知道是什么寻找问题。原以为gradle不识别属性,charset还是windows-1251,但调试显示我错了。

嗯,这是我尝试解决问题的完整列表: 1)在idea.exe.vmoptions和idea64.exe.vmoptions中设置-Dfile.encoding=UTF-8并重启。没有帮助。 2) 在 IntelliJ IDEA -> Settings -> Editor -> File Encodings 各处设置 UTF-8。没有帮助。 3) 将 gradle 编译器编码设置为 utf-8。没有帮助。 4)设置gradle jvm选项org.gradle.jvmargs=-Dfile.encoding=utf-8。没有帮助。 5) 检查 Windows 是否将俄语语言作为不支持 unicode 以支持西里尔文的程序的默认设置。没有帮助。

我不确定 gradle 有什么问题,因为没有 gradle 的干净项目效果很好,控制台输出还可以。但是对于 gradle,西里尔符号是不正确的。此外,我尝试使用 getBytes(charset) 和 new 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 中,如何检查它?或者如何让 gradle 对控制台输出使用另一种编码?或者即使没有 gradle 的项目中的输出是正确的,它仍然是 IntelliJ IDEA 的东西?

我觉得自己像个侦探,但我已经停滞不前了,被困在那种情况下。如果有人帮助我,我将不胜感激。

【问题讨论】:

  • 如果你用十六进制编辑器查看D.java,字符串中的字符占用多少字节?看起来文件不是UTF-8,而是win-1251
  • 二手十六进制编辑器 Neo。它显示我的字符串如下:Проверка работоспособности Р РЁ 字节:d0 9f d1 80 d0 be d0 b2 d0 b5 d1 80 d0 ba d0 b0 20 d1 80 d0 b0 d0 b1 d0 be d1 82 d0 be d1 81 d0 bf d0 be d1 81 d0 be d0 b1 d0 bd d0 be d1 81 d1 82 d0 b8 20 d0 98 20 d0 a8 看起来不错,d0 9f 真的是 'П' 字符。
  • 啊,这似乎是 Gradle 特有的,是不是 stackoverflow.com/questions/21267234/…
  • 我不确定问题到底出在哪里,但似乎问题确实是特定于 gradle 的。我尝试在链接中添加systemProp.file.encoding=utf-8,也做到了:build { doLast { println System.getProperty("file.encoding") } } 输出为:&gt; Task :build utf-8
  • 我也有这个任务:task info { doLast { println System.getProperty("file.encoding") println "Gradle — система автоматической сборки, построенная на принципах Apache Ant и Apache Maven, но предоставляющая DSL на языке Groovy вместо традиционной XML-образной формы представления конфигурации проекта. И Ш" } } 当我运行时,我得到这个:&gt; Task :info utf-8 Gradle � ������� �������������� ������, ����������� �� ��������� Apache Ant � Apache Maven, �� ��������������� DSL �� ����� Groovy ������ ������������ XML-�������� ����� ������������� ������������ �������. � �

标签: java gradle intellij-idea encoding utf-8


【解决方案1】:

Run\Edit Configurations,选择你的运行配置并在VM Options字段中写入-Dfile.encoding=UTF-8。这为我解决了问题。

【讨论】:

    【解决方案2】:

    我遇到了类似的问题。 这是一个 Gradle-IntelliJ-on-non-ascii-language-version-Windows 特定问题。

    我通过以下方式解决了这个问题:

    • 在项目的gradle.properties文件中设置systemProp.file.encoding=utf-8
    • 在 IntelliJ 上,转到 Settings -&gt; Tools -&gt; Terminal -&gt; Application Settings 并将 cmd.exe /K "chcp 65001" 设置为“Shell 路径”

    默认情况下,shell 路径应该只是cmd.exe

    使用属性文件中的属性值应该有助于在 IntelliJ 上使用 Gradle 工具构建工作, 并且shell路径设置解析集成终端上的编码。

    如果您在 IntelliJ 之外使用 cmd,而不是从 IntelliJ 上的集成终端,只需在控制台上调用 chcp 65001。 这将在 cmd 控制台上设置字符编码UTF-8

    【讨论】:

      【解决方案3】:

      将字体更改为能够正确显示设置中所有字符的字体(macOS 上的首选项)|编辑 |字体 | 字体设置。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-03-31
        • 2019-03-25
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多