如何解決java linux檔中文亂碼問題
java linux檔案中文亂碼的解決方法:1、下載jdk1.8的sun原始碼;2、將Font的創建從實體字體改為邏輯字體;3、重啟服務即可。
本文操作環境:linux5.9.8系統,jdk1.8,Dell G3電腦。
如何解決java linux檔案中文亂碼問題?
#Linux環境下Java中文亂碼解決方案
相信很多朋友遇到過Java的亂碼問題,最近我也在解決一個「使用文字產生圖片過程中中文以及特殊字元亂碼」的問題;花了我大量時間,Debug了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); }
目標當然是想在開啟test. png的時候看到如下場景:
在本地調試沒問題之後,就放到了測試機(Linux)上面去執行了,執行結果簡直撲街:
jdk1.8的sun源碼下載
奉行程式設計師一貫作風:既然有問題,那就Debug!
坑爹的是現在的原始碼包已經不包含sun包的程式碼了!
幸好java官方確認OpenJDK的程式碼基本上和JVM源碼一致,可以直接從OpenJDK8u進行下載:jdk8u
至於如何使用源碼debug,這個就不寫了··· 這都不會基本也就別看這文章了
定位問題
直接下載好源碼,遠端斷點,伺服器執行,在debug中先發現了第一個產生本地和測試伺服器不一致的程式碼:
原來JVM建立Font的時候會使用FontManagerFactory取得FontManager,而不同的系統所使用的FontManager是不同的! Mac用的是CFontManager,Linux用的是X11FontManager!
那麼這兩個FontManager的不同會導致什麼不同呢?
CFontManager會建立CFont作為Font2D,這個CFont是JVM專門為mac創建的類,看類別和方法的註解可以知道在mac環境下有時候物理字體會被CFont包裝,而這是在native程式碼中完成的:
X11FontManager所建立的Font2D是包含了邏輯字體和實體字體的集合。 X11FontManager繼承了FcFontManager,FcFontManager繼承了SunFontManager;我們來看看X11FontManager的loadFonts()方法,直接使用了SunFontManager的loadFonts(),SunFontManager的loadFonts()方法載入了物理字體,SunFontManager實作了FontManager的preferLocaleFonts()方法,載入了邏輯字體:
#邏輯字體與物理字體
代碼debug到這邊基本上已經確認了是不同環境的字體載入問題,那麼在debug linux環境的時候發現的邏輯字體和實體字體是什麼東西呢?
實體字型
實體字型是實際的字型庫,包含字形資料和資料表,這些資料和資料表使用字型技術(如TrueType 或PostScript Type 1)將字元序列對應到字形序列。 Java Platform 的所有實作都支援 TrueType 字型;對其他字型技術的支援是與實作相關的。實體字體可以使用字體名稱,如 Helvetica、Palatino、HonMincho 或任意數量的其他字體名稱。通常,每種物理字體只支援有限的書寫系統集合,例如,只支援拉丁文字符,或只支援日文和基本拉丁文。可用的實體字體集合隨配置的不同而有所不同。要求特定字體的應用程式可以使用 createFont 方法來捆綁這些字體,並對其進行實例化。
邏輯字體
邏輯字體是由必須受所有 Java 執行時間環境支援的 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中文網其他相關文章!

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

Linux系統的五個基本組件是:1.內核,2.系統庫,3.系統實用程序,4.圖形用戶界面,5.應用程序。內核管理硬件資源,系統庫提供預編譯函數,系統實用程序用於系統管理,GUI提供可視化交互,應用程序利用這些組件實現功能。

PHP適用於Web開發和內容管理系統,Python適合數據科學、機器學習和自動化腳本。 1.PHP在構建快速、可擴展的網站和應用程序方面表現出色,常用於WordPress等CMS。 2.Python在數據科學和機器學習領域表現卓越,擁有豐富的庫如NumPy和TensorFlow。

PHPhassignificantlyimpactedwebdevelopmentandextendsbeyondit.1)ItpowersmajorplatformslikeWordPressandexcelsindatabaseinteractions.2)PHP'sadaptabilityallowsittoscaleforlargeapplicationsusingframeworkslikeLaravel.3)Beyondweb,PHPisusedincommand-linescrip

雖然 Notepad 無法直接運行 Java 代碼,但可以通過借助其他工具實現:使用命令行編譯器 (javac) 編譯代碼,生成字節碼文件 (filename.class)。使用 Java 解釋器 (java) 解釋字節碼,執行代碼並輸出結果。

要查看 Git 倉庫地址,請執行以下步驟:1. 打開命令行並導航到倉庫目錄;2. 運行 "git remote -v" 命令;3. 查看輸出中的倉庫名稱及其相應的地址。

Linux的主要用途包括:1.服務器操作系統,2.嵌入式系統,3.桌面操作系統,4.開發和測試環境。 Linux在這些領域表現出色,提供了穩定性、安全性和高效的開發工具。

要安裝 Laravel,需依序進行以下步驟:安裝 Composer(適用於 macOS/Linux 和 Windows)安裝 Laravel 安裝器創建新項目啟動服務訪問應用程序(網址:http://127.0.0.1:8000)設置數據庫連接(如果需要)
