Java linux ファイルの中国語文字化けの解決策: 1. jdk1.8 の sun ソース コードをダウンロードする; 2. フォントの作成を物理フォントから論理フォントに変更する; 3. サービスを再起動する。
この記事の動作環境: linux5.9.8 システム、jdk1.8、Dell G3 コンピューター。
Java linux ファイルの中国語文字化けの問題を解決するにはどうすればよいですか?
Linux 環境での Java 中国語文字化けの解決方法
Java で文字化けに遭遇した友人は多いと思いますが、私も最近、「テキストを使用して画像を生成する過程で中国語や特殊文字が文字化けする」問題を解決しました。デバッグに非常に時間がかかりました。 sun.font と sun.awt. の下にあるさまざまなソースコードを参照して、最終的にメカニズムを理解し、現在の問題を解決しました。問題解決のプロセスを書き留めて、将来この問題に遭遇しないように記録します。
実行したいコードは次のとおりです (非常に簡略化されていますが、意味は同じです):
public static void main(String[] args) throws IOException { File file = new File("test.png"); Font font = new Font("宋体", Font.PLAIN, 10); BufferedImage bi = new BufferedImage(400, 200, BufferedImage.TYPE_INT_ARGB); Graphics2D g2 = (Graphics2D) bi.getGraphics(); g2.setBackground(Color.WHITE); g2.clearRect(0, 0, 400, 200); g2.setFont(font); g2.setColor(Color.BLACK); g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); g2.drawString("为什么没有(ꐚꌒꑿꆺ)(ꐚꌒꑿꆺ)这名字特殊不?@¥¥¥ 为什么没有(ꐚꌒꑿꆺ)(ꐚꌒꑿꆺ)这名字特 ", 0, 10); g2.dispose(); ImageIO.write(bi, PNG, file); }
目標はもちろんオープン テストです。 .png で、次のようなシーンが見られました:
ローカル デバッグが問題なかった後、テスト マシン (Linux) に配置して実行しました。結果は単純に圧倒的です:
プログラマーの一貫したスタイルに従います。問題がある場合は、デバッグしてください。
重要なのは、現在のソース コード パッケージには sun パッケージのコードが含まれていないということです。
幸いなことに、OpenJDK のコードは基本的に JVM のソース コードと同じであることが Java によって公式に確認されており、OpenJDK8u から直接ダウンロードできます: jdk8u
ソース コードを使用してデバッグする方法については、これは書きません...これは基本的ですらないので、この記事は読まないでください
ソース コードを直接ダウンロードし、リモート ブレークポイントを使用して、サーバーを実行します。デバッグ中に、ローカル サーバーとテスト サーバーの間で不一致を引き起こす最初のコードを初めて発見しました。
JVM がフォントを作成するときに、FontManagerFactory を使用してフォントを取得することがわかりました。 FontManager であり、異なるシステムでは異なる FontManager が使用されます。 Mac は CFontManager を使用しますが、Linux は X11FontManager を使用します。
それでは、これら 2 つの FontManager の違いは何でしょうか?
CFontManager は CFont を Font2D として作成します。この CFont は Mac 専用に JVM によって作成されたクラスです。クラスとメソッドのコメントを見ると、Mac では物理フォントが CFont によってラップされる場合があることがわかります。
X11FontManager によって作成された Font2D は、論理フォントと物理フォントを含むコレクションです。 X11FontManagerはFcFontManagerを継承し、FcFontManagerはSunFontManagerを継承します。SunFontManagerのloadFonts()を直接使用するX11FontManagerのloadFonts()メソッドを見てみましょう。SunFontManagerのloadFonts()メソッドは物理フォントをロードします。SunFontManagerはFontManagerのpreferLocaleFonts()を実装します。ロードされた論理フォント:
debug的源码很多,但是此次问题的关键点就在这里了,其它debug内容就不贴了。
既然已经确认了本地(mac环境)是native的代码帮我们做了物理字体的封装,转换成了CFont进行渲染,而Linux环境的X11FontManager只是帮我们加载了物理字体和逻辑字体,但是却需要我们自己进行选择,那么解决问题的第一步就显而易见了:将Font的创建从物理字体改为逻辑字体
1 // Serif、SansSerif、Monospaced、Dialog 和 DialogInput 随意选择 2 Font font = new Font("Serif", Font.PLAIN, 10);
改完以后执行代码,仍然是乱码!继续Debug,发现是Linux上逻辑字体Serif映射的物理字体没有中文字体和对应的特殊符号字体,这就很简单了,直接在Linux上安装中文字体(simsun.ttf),再安装特殊符号“ꐚꌒꑿꆺ”可显示的字体(mysi.ttf),将这两个字体也放到了jdk的fonts目录(JAVA_HOME/jre/lib/fonts)下。文章后面有Linux字体安装方法。
完成上面的改动之后,重启服务,再次执行成功显示!热烈庆祝~~~~
以上的改动已经可以解决中文和特殊字符乱码问题,但是我在Debug过程中发现在逻辑字体加载过程中,JVM会参考一个配置文件,代码在sun.awt.FontConfiguration中,这个配置类完成了逻辑字体和物理字体的映射,也指导了SunFontManager创建逻辑字体,而这个FontConfiguration读取的配置文件就是fontconfig.properties,这个配置文件目录是JAVA_HOME/jre/lib
查阅了一下资料,JVM字体配置文件的加载顺序如下:
JAVA_HOME/jre/lib/fontconfig.OS.Version.properties
JAVA_HOME/jre/lib/fontconfig.OS.Version.bfc
JAVA_HOME/jre/lib/fontconfig.OS.properties
JAVA_HOME/jre/lib/fontconfig.OS.bfc
JAVA_HOME/jre/lib/fontconfig.Version.properties
JAVA_HOME/jre/lib/fontconfig.Version.bfc
JAVA_HOME/jre/lib/fontconfig.properties
JAVA_HOME/jre/lib/fontconfig.bfc
OS是系统,例如:Linux、CentOs、RedHat等;Version是版本号
在这个配置文件中可以修改逻辑字体与物理字体的对应关系,也就是说可以手动的修改Serif、SansSerif、Monospaced、Dialog 和 DialogInput这五个逻辑字体在不同场景下所使用的真正物理字体。
举个栗子,下面的配置将serif.plain逻辑字体的中文使用simsun.ttf,拉丁文使用java自带字体:
# @(#)linux.fontconfig.SuSE.properties 1.2 03/10/17 # # Copyright 2003 Sun Microsystems, Inc. All rights reserved. # # Version version=1 # Component Font Mappings serif.plain.chinese=-misc-simsun-medium-r-normal--*-%d-*-*-c-*-iso10646-1 serif.plain.latin-1=-b&h-lucidabright-medium-r-normal--*-%d-*-*-p-*-iso8859-1 # Search Sequences sequence.allfonts=latin-1,chinese # Exclusion Ranges # Font File Names filename.-misc-simsun-medium-r-normal--*-%d-*-*-c-*-iso10646-1=/usr/share/fonts/myfonts/simsun.ttf
PS:以上所有操作基本都需要root权限
推荐学习:《linux视频教程》
以上がJava Linuxファイルの中国語文字化け問題を解決する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。