这里发生了什么?为什么当我使用 utf-8 读取文件时,它会在控制台中输出问号?
这是一个最小的工作示例:
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import static org.apache.commons.io.FileUtils.readFileToString;
import static org.apache.commons.io.FileUtils.writeStringToFile;
public class Main {
public static void main(String... args) throws IOException {
System.out.println("---------");
System.out.println(Charset.defaultCharset());
System.out.println("æ ø å");
System.out.println("æ ø å");
System.out.println("æ ø å");
File inputFile = new File(System.getProperty("user.dir") + "/input.md");
File outputFile = new File(System.getProperty("user.dir") + "/output.md");
String content, encoding;
System.out.println("--------- windows-1252");
encoding = "windows-1252";
content = readFileToString(inputFile, encoding);
System.out.println(content);
System.out.println("--------- iso-8859-1");
encoding = "iso-8859-1";
content = readFileToString(inputFile, encoding);
System.out.println(content);
System.out.println("--------- utf-8");
encoding = "utf-8";
content = readFileToString(inputFile, encoding);
System.out.println(content);
writeStringToFile(outputFile, content, encoding);
}
}
其中
input.md
包含:(以 UTF-8 编码)
This is input.md. 'æ' 'ø' 'å'
运行上面的代码会产生
---------
windows-1252
æ ø å
æ ø å
æ ø å
--------- windows-1252
This is file C. 'æ' 'ø' 'å'.
--------- iso-8859-1
This is file C. 'æ' 'ø' 'å'.
--------- utf-8
This is file C. '�' '�' '�'.
为什么当我使用 UTF-8 读取文件时会出现
�
?这特别奇怪,因为文件是用 UTF-8 编码的。
更新:我的控制台设置为“UTF-8”:
这是从输入文件中提取的字符串中每个字符的十六进制值的屏幕截图:
这是隔离的十六进制的更好屏幕截图:
代码对我来说看起来不错,你的
output.md
文件看起来也不错。所以这很可能只是控制台输出的问题。
您正在尝试的 Unicode 字符在 Windows-1252 和 ISO-8859-1 中被编码为相同的单字节(
æ = 0xE6
、ø = 0xF8
、å = 0xE5
),但在 UTF-8 中被编码为多个字节(æ = 0xC3 0xA6
、ø = 0xC3 0xB8
、å = 0xC3 0xA5
)。
将 UTF-8 编码文件读取为 Windows-1252 或 ISO-8859-1 将单独解码每个字节,生成一个
string
,其中每个字节包含单独的 char
,并且这些 char
将具有相同的以字节为单位的数值。所以,你应该最终得到一个包含字符string
、0x00C3 0x00A6
和0x00C3 0x00B8
的0x00C3 0x00A5
。将这些 char
作为 Windows-1252 应该 输出到控制台,显示为 æ ø Ã¥
,而不是 æ ø å
。
另一方面,将 UTF-8 编码的文件读取为 UTF-8 将正确解码该文件,生成带有
string
、char
、0x00E6
和 0x00F8
的 0x00E5
。将 string
写入 UTF-8 编码文件应该会生成正确的字节序列(0xC3 0xA6
、0xC3 0xB8
和 0xC3 0xA5
),但输出与 Windows-1252 相同的 string
会有数据丢失的风险,但是您应该会按预期看到æ ø å
,因为 Windows-1252 确实支持这些 Unicode 字符。
所以,你的结果实际上与我的预期相反。尽管
Charset.defaultCharset()
正在报告 Windows-1252,但我怀疑您的控制台实际上正在使用不同的字符集进行输出。
我建议您打印出
char
字符串中各个 content
的数值,以准确了解每种编码实际上如何解码 input.md
。您应该获得我上面提到的char
值。
对于有类似问题的人来说,问题在于控制台的编码(正如@Remy Lebeau 也指出的那样)。
我按照这个answer
解决了这个问题实际上,我按照@Nicolas 在评论中对提到的答案的回答:
也可以通过“帮助”>“编辑自定义虚拟机选项”访问此操作...然后重新启动 IntelliJ。我确实尝试了一切:更改 IntelliJ 中各处的编码设置,更改由属性文件、build.gradle 文件、IntelliJ、运行配置、环境变量等设置的 JVM 选项。还尝试更改系统范围的编码,但没有任何效果,但这个
现在我得到了预期的输出:
我遇到了类似的问题,我发现我系统上的some JDK 产生了
file.encoding
的 Cp1252
而不是 UTF-8。我不知道为什么。
然后您可以添加
-Dfile.encoding=UTF-8
,或者如果您使用 Gradle,则只需将 org.gradle.jvmargs=-Dfile.encoding=UTF-8
添加到您的 ~/.gradle/gradle.properties
(%userprofile%\.gradle\gradle.properties
) 或在项目级别添加到您的 gradle.properties
。
或者尝试重新安装所需的 JDK
file.encoding
。