ホームページ  >  記事  >  運用・保守  >  Java Linuxファイルの中国語文字化け問題を解決する方法

Java Linuxファイルの中国語文字化け問題を解決する方法

藏色散人
藏色散人オリジナル
2021-12-14 14:33:335672ブラウズ

Java linux ファイルの中国語文字化けの解決策: 1. jdk1.8 の sun ソース コードをダウンロードする; 2. フォントの作成を物理フォントから論理フォントに変更する; 3. サービスを再起動する。

Java Linuxファイルの中国語文字化け問題を解決する方法

この記事の動作環境: 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) に配置して実行しました。結果は単純に圧倒的です:

jdk1.8 sun ソース コードのダウンロード

プログラマーの一貫したスタイルに従います。問題がある場合は、デバッグしてください。
重要なのは、現在のソース コード パッケージには 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()を実装します。ロードされた論理フォント:

#論理フォントと物理フォント

ここでのコード デバッグ Bian は基本的に、次のことを確認しました。さまざまな環境でのフォント読み込みの問題 では、Linux 環境のデバッグ時に検出される論理フォントと物理フォントとは何でしょうか?

物理フォント

物理フォントは、TrueType や PostScript Type 1 などのフォント テクノロジを使用して文字のシーケンスをグリフのシーケンスにマップするグリフ データとテーブルを含む実際のフォント ライブラリです。 Java プラットフォームのすべての実装は TrueType フォントをサポートしますが、他のフォント テクノロジのサポートは実装に依存します。物理フォントでは、Helvetica、Palatino、HonMincho などのフォント名、またはその他の任意の数のフォント名を使用できます。通常、各物理フォントは、ラテン文字のみ、または日本語と基本ラテン文字のみなど、限られたセットの書記体系のみをサポートします。使用可能な物理フォントのセットは構成によって異なります。特定のフォントを必要とするアプリケーションは、createFont メソッドを使用してこれらのフォントをバンドルし、インスタンス化できます。

論理フォント

論理フォントは、Java プラットフォームによって定義された 5 つのフォント ファミリであり、すべての Java ランタイム環境 (Serif、SansSerif、Monospaced、Dialog、および DialogInput) でサポートされている必要があります。これらの論理フォントは実際のフォント ライブラリではありません。さらに、論理フォント名を物理フォントにマップするのは Java ランタイム環境です。マッピングは実装であり、通常はロケールに依存するため、マッピングが提供する外観と仕様は異なります。通常、膨大な範囲の文字をカバーするために、各論理フォント名は複数の物理フォントにマップされます。

问题解决

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字体安装方法。

完成上面的改动之后,重启服务,再次执行成功显示!热烈庆祝~~~~

JVM逻辑字体映射配置

以上的改动已经可以解决中文和特殊字符乱码问题,但是我在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

Linux安装字体

  • Linux字体目录:/usr/share/fonts
  • 在fonts下面新建一个目录,例如:mkdir myfonts
  • 将需要安装的字体放到新建目录下面,例如:cp ~/test/simsun.ttf /usr/share/fonts/myfonts
  • 进入到myfonts目录:cd /usr/share/fonts/myfonts
  • 执行如下命令:
    • mkfontscale
    • mkfontdir
    • fc-cache -fv
  • 查看是否已经安装对应的字体:fc-list
  • fc-cache -fv 命令用来刷新linux的字体缓存,使其立刻生效

PS:以上所有操作基本都需要root权限

推荐学习:《linux视频教程

以上がJava Linuxファイルの中国語文字化け問題を解決する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。