java - Gradle项目中的IntelliJ IDEA编码问题

标签 java gradle intellij-idea encoding utf-8

通常,我在这里不问任何问题,但是我面对的问题是如此令人毛骨悚然,以至于我无法再单独解决它,我已经筋疲力尽了。无论如何,我将描述所发现的一切,并且发现许多我想相信会帮助某人帮助我的有趣事情。

软件版本:
-操作系统:Windows 10 Pro版本:1909内部版本:18363.720
-IntelliJ IDEA:2019.2.4旗舰版
-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文本编码为正确的字节序列:
字符串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

之后,我就死了。 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()'.

在文件中:
Проверка работоспособности � Ш

另外,控制台中的输出是促使我确定问题出在哪里的第一件事,我只是在编码,发现西里尔字母“И”确实有问题。我试图一次又一次地解决它...现在我在这里,因为我处于死胡同,我尝试了所有在类似问题和有关编码问题的主题中发现的所有内容,一些有关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->设置->编辑器->文件编码中设置UTF-8。没帮助
3)将gradle编译器编码设置为utf-8。没帮助
4)设置gradle jvm选项org.gradle.jvmargs = -Dfile.encoding = utf-8。没帮助
5)检查Windows是否将俄语作为默认语言,用于不支持西里尔文支持的unicode的程序。没帮助

我不确定gradle有什么问题,因为没有gradle的干净项目效果很好,控制台输出也可以。但是使用gradle时,西里尔符号是不正确的。另外,我尝试以某种方式使用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编码,输出正确。但是,即使Encoder正常工作,System.out.println在控制台中也会打印出一些不合理的内容。我不知道这是怎么回事(对不起的讲话很抱歉),如果问题确实存在,应该如何检查?还是如何让gradle将其他编码用于控制台输出?也许即使没有gradle的项目中的输出正确,IntelliJ IDEA还是有问题吗?

我觉得自己像个侦探,但在那种情况下我陷入僵局,陷入困境。如果有人帮助我,我将不胜感激。

最佳答案

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

关于java - Gradle项目中的IntelliJ IDEA编码问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60838495/

相关文章:

java - 使用 jgrapht 自定义边缘

java - 在圆形 JLabel 图像周围创建可点击区域

java - 抛出的优先级以及同一异常的抛出

java - 使用嵌入式 Cassandra 服务器测试 Cassandra-Spark 作业的 Java 示例

android - 如何在Gradle中排除.jar依赖项

gradle - 迁移到 AndroidX 后出现错误 : cannot find symbol import com. google.firebase.iid.InstanceIdResult

java - Gradle buildConfigField 非法前向引用

java - 使用外部库将项目部署到 glassfish 后出现 NoClassDefFoundError

java - 我的计算机上可以有两个版本的 JDK 吗?

intellij-idea - 如何将自定义构建脚本添加到 IDEA?