java讀取文件內(nèi)容中文亂碼

問題描述

java程序通過new java.io.FileReader(file)讀取文件低千,文件內(nèi)容有中文,最終讀取到的中文產(chǎn)生亂碼馏颂。

閱讀代碼

package java.io;

public class FileReader extends InputStreamReader {
    public FileReader(File file) throws FileNotFoundException {
        super(new FileInputStream(file));
    }
}
package java.io;

import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import sun.nio.cs.StreamDecoder;

public class InputStreamReader extends Reader {

    private final StreamDecoder sd;

    public InputStreamReader(InputStream in) {
        super(in);
        try {
            sd = StreamDecoder.forInputStreamReader(in, this, (String)null); // ## check lock object
        } catch (UnsupportedEncodingException e) {
            // The default encoding should always be available
            throw new Error(e);
        }
    }

    public InputStreamReader(InputStream in, String charsetName)
        throws UnsupportedEncodingException
    {
        super(in);
        if (charsetName == null)
            throw new NullPointerException("charsetName");
        sd = StreamDecoder.forInputStreamReader(in, this, charsetName);
    }

    public InputStreamReader(InputStream in, Charset cs) {
        super(in);
        if (cs == null)
            throw new NullPointerException("charset");
        sd = StreamDecoder.forInputStreamReader(in, this, cs);
    }
}
package sun.nio.cs;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.ReadableByteChannel;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CoderResult;
import java.nio.charset.CodingErrorAction;
import java.nio.charset.IllegalCharsetNameException;

public class StreamDecoder extends Reader {
    private static final int MIN_BYTE_BUFFER_SIZE = 32;
    private static final int DEFAULT_BYTE_BUFFER_SIZE = 8192;
    private volatile boolean isOpen;
    private boolean haveLeftoverChar;
    private char leftoverChar;
    private static volatile boolean channelsAvailable = true;
    private Charset cs;
    private CharsetDecoder decoder;
    private ByteBuffer bb;
    private InputStream in;
    private ReadableByteChannel ch;

    public static StreamDecoder forInputStreamReader(InputStream var0, Object var1, String var2) throws UnsupportedEncodingException {
        String var3 = var2;
        if (var2 == null) {
            var3 = Charset.defaultCharset().name();
        }

        try {
            if (Charset.isSupported(var3)) {
                return new StreamDecoder(var0, var1, Charset.forName(var3));
            }
        } catch (IllegalCharsetNameException var5) {
        }

        throw new UnsupportedEncodingException(var3);
    }
}
package java.nio.charset;

import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.spi.CharsetProvider;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Locale;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.ServiceLoader;
import java.util.ServiceConfigurationError;
import java.util.SortedMap;
import java.util.TreeMap;
import sun.misc.ASCIICaseInsensitiveComparator;
import sun.nio.cs.StandardCharsets;
import sun.nio.cs.ThreadLocalCoders;
import sun.security.action.GetPropertyAction;

public abstract class Charset
    implements Comparable<Charset>
{

    private static volatile Charset defaultCharset;

    /**
     * Returns the default charset of this Java virtual machine.
     *
     * <p> The default charset is determined during virtual-machine startup and
     * typically depends upon the locale and charset of the underlying
     * operating system.
     *
     * @return  A charset object for the default charset
     *
     * @since 1.5
     */
    public static Charset defaultCharset() {
        if (defaultCharset == null) {
            synchronized (Charset.class) {
                String csn = AccessController.doPrivileged(
                    new GetPropertyAction("file.encoding"));
                Charset cs = lookup(csn);
                if (cs != null)
                    defaultCharset = cs;
                else
                    defaultCharset = forName("UTF-8");
            }
        }
        return defaultCharset;
    }

    public final String name() {
        return name;
    }

}

從方法注釋可以看出示血,默認字符集是在虛擬機啟動時確定的,并且通常取決于底層操作系統(tǒng)的區(qū)域和字符集救拉。

package sun.security.action;

import java.security.AccessController;
import java.security.PrivilegedAction;

public class GetPropertyAction implements PrivilegedAction<String> {
    private String theProp;
    private String defaultVal;

    public GetPropertyAction(String var1) {
        this.theProp = var1;
    }

    public GetPropertyAction(String var1, String var2) {
        this.theProp = var1;
        this.defaultVal = var2;
    }

    public String run() {
        String var1 = System.getProperty(this.theProp);
        return var1 == null ? this.defaultVal : var1;
    }

    public static String privilegedGetProperty(String var0) {
        return System.getSecurityManager() == null ? System.getProperty(var0) : (String)AccessController.doPrivileged(new GetPropertyAction(var0));
    }

    public static String privilegedGetProperty(String var0, String var1) {
        return System.getSecurityManager() == null ? System.getProperty(var0, var1) : (String)AccessController.doPrivileged(new GetPropertyAction(var0, var1));
    }
}

可以看出通過System.getProperty(this.theProp)獲取系統(tǒng)屬性难审。
如果你需要更改JVM的默認字符集,可以通過在啟動JVM時指定-Dfile.encoding屬性來實現(xiàn)亿絮。例如告喊,你可以使用-Dfile.encoding=UTF-8來將默認字符集設(shè)置為UTF-8。
需要注意的是派昧,操作系統(tǒng)字符集的設(shè)置也有相應的優(yōu)先級黔姜。通常,LC_ALL設(shè)置具有最高的優(yōu)先級蒂萎,它可以強制設(shè)置字符集秆吵。如果沒有設(shè)置LC_ALL,那么會考慮LC_設(shè)置五慈,最后是LANG設(shè)置帮毁。LANG是LC_的默認值,而LC_ALL比LC_的優(yōu)先級別高豺撑,設(shè)置完LC_ALL之后烈疚,會強制重置LC_各個值,如果不將LC_ALL重新設(shè)置為空聪轿,則再無法設(shè)置LC_*的單個值 爷肝。

排查

  • java程序沒有設(shè)置file.encoding
  • Linux中使用locale查看系統(tǒng)編碼發(fā)現(xiàn)使用的是GBK,到此亂碼原因找到。

解決方法

  • java程序啟動時指定-Dfile.encoding=UTF-8灯抛。
    示例:java -Dfile.encoding=UTF-8 -jar demo.jar
  • 修改操作系統(tǒng)默認字符集編碼金赦。
/etc/profile是系統(tǒng)級的配置文件,它應用于所有用戶对嚼。
~/.bash_profile是用戶級的配置文件夹抗,它只適用于當前登錄用戶。
系統(tǒng)會首先加載/etc/profile纵竖,然后加載~/.bash_profile漠烧。
這意味著用戶級的配置文件會覆蓋系統(tǒng)級的配置文件,因為后者的配置會在前者之后加載靡砌。

1已脓、sudo vim ~/.bash_profile
2、export LC_ALL=en_US.UTF-8
3通殃、source ~/.bash_profile
4度液、重啟java程序

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市画舌,隨后出現(xiàn)的幾起案子堕担,更是在濱河造成了極大的恐慌,老刑警劉巖曲聂,帶你破解...
    沈念sama閱讀 222,183評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件霹购,死亡現(xiàn)場離奇詭異,居然都是意外死亡句葵,警方通過查閱死者的電腦和手機厕鹃,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,850評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來乍丈,“玉大人剂碴,你說我怎么就攤上這事∏嶙ǎ” “怎么了忆矛?”我有些...
    開封第一講書人閱讀 168,766評論 0 361
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長窖梁,這世上最難降的妖魔是什么剧腻? 我笑而不...
    開封第一講書人閱讀 59,854評論 1 299
  • 正文 為了忘掉前任港庄,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己采驻,他們只是感情好审胚,可當我...
    茶點故事閱讀 68,871評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著礼旅,像睡著了一般膳叨。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上痘系,一...
    開封第一講書人閱讀 52,457評論 1 311
  • 那天菲嘴,我揣著相機與錄音,去河邊找鬼汰翠。 笑死龄坪,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的奴璃。 我是一名探鬼主播悉默,決...
    沈念sama閱讀 40,999評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼城豁,長吁一口氣:“原來是場噩夢啊……” “哼苟穆!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起唱星,我...
    開封第一講書人閱讀 39,914評論 0 277
  • 序言:老撾萬榮一對情侶失蹤雳旅,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后间聊,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體攒盈,經(jīng)...
    沈念sama閱讀 46,465評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,543評論 3 342
  • 正文 我和宋清朗相戀三年哎榴,在試婚紗的時候發(fā)現(xiàn)自己被綠了型豁。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,675評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡尚蝌,死狀恐怖迎变,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情飘言,我是刑警寧澤衣形,帶...
    沈念sama閱讀 36,354評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站姿鸿,受9級特大地震影響谆吴,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜苛预,卻給世界環(huán)境...
    茶點故事閱讀 42,029評論 3 335
  • 文/蒙蒙 一句狼、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧热某,春花似錦腻菇、人聲如沸突诬。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,514評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽旺隙。三九已至,卻和暖如春骏令,著一層夾襖步出監(jiān)牢的瞬間蔬捷,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,616評論 1 274
  • 我被黑心中介騙來泰國打工榔袋, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留周拐,地道東北人。 一個月前我還...
    沈念sama閱讀 49,091評論 3 378
  • 正文 我出身青樓凰兑,卻偏偏與公主長得像妥粟,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子吏够,可洞房花燭夜當晚...
    茶點故事閱讀 45,685評論 2 360

推薦閱讀更多精彩內(nèi)容

  • 運行環(huán)境:Windows 10 勾给;IDEA-2019.3;Tomcat 9.0.24锅知;jdk 1.8.0_221播急;...
    _小毛驢閱讀 202評論 0 0
  • 前言 計算機中儲存的信息都是用二進制數(shù)表示的;而我們在屏幕上看到的英文售睹、漢字等字符是二進制數(shù)轉(zhuǎn)換之后的結(jié)果桩警。通俗的...
    LordZhou閱讀 4,600評論 0 0
  • 背景 今天用mysql5.7 client 登錄數(shù)據(jù)庫,用query 查詢展示漢字沒問題昌妹,但命令行輸入中文會直接變...
    龍嘯_076d閱讀 1,208評論 0 0
  • 問題:使用一臺Linux系統(tǒng)的機器捶枢,終端總是顯示有亂碼,不是中文亂碼飞崖,看起來像是英文亂碼烂叔,我這強迫癥又受不了了 解...
    韓小早兒閱讀 920評論 0 1
  • **問題背景**:javaWeb項目導出文件名亂碼。本地window7調(diào)試項目導出文件名正常蚜厉,線上linux(ce...
    Aronc閱讀 841評論 0 0