亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Java中常見的編碼集問題總結(jié)

 更新時間:2023年02月16日 08:39:15   作者:哪吒編程  
這篇文章主要為大家整理了一些Java中常見的編碼集問題,文中的示例代碼講解詳細(xì),對我們深入理解Java有一定的幫助,感興趣的小伙伴可以了解一下

一、遇到一個問題

1、讀取CSV文件

package com.guor.demo.charset;

import java.io.BufferedReader;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class CommonUtils {
    public static List<Map<String, Object>> readCSVToList(String filePath) throws Exception {
        List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
        BufferedReader reader = null;
        try {
            reader = new BufferedReader(new FileReader(filePath));
            String[] headtilte = reader.readLine().split(",");
            String line = null;
            while ((line = reader.readLine()) != null) {
                HashMap<String, Object> hashMap = new HashMap<String, Object>();
                String[] itemArray = line.split(",");
                for (int i = 0; i < itemArray.length; i++) {
                    hashMap.put(headtilte[i], itemArray[i]);
                }
                list.add(hashMap);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (null != reader) {
                reader.close();
            }
        }
        return list;
    }

    public static void main(String[] args) throws Exception {
        String filePath = "H:\\CSDN\\netty\\編碼集問題\\test.csv";
        System.out.println(readCSVToList(filePath));
    }
}

2、控制臺輸出

這是什么鬼?

原來我的csv文件的編碼集是帶BOM的UTF-8,沒聽過啊,眾里尋他千百度。

二、帶有BOM的UTF-8

1、BOM

在UCS 編碼中有一個叫做 “Zero Width No-Break Space” ,中文譯名作“零寬無間斷間隔”的字符,它的編碼是 FEFF。而 FEFF 在 UCS 中是不存在的字符,所以不應(yīng)該出現(xiàn)在實(shí)際傳輸中。UCS 規(guī)范建議我們在傳輸字節(jié)流前,先傳輸字符 “Zero Width No-Break Space”。這樣如果接收者收到 FEFF,就表明這個字節(jié)流是 Big-Endian 的;如果收到FFFE,就表明這個字節(jié)流是 Little- Endian 的。因此字符 “Zero Width No-Break Space” (“零寬無間斷間隔”)又被稱作 BOM。

2、UTF-8

UTF-8(8位元,Universal Character Set/Unicode Transformation Format)是針對Unicode的一種可變長度字符編碼。它可以用來表示Unicode標(biāo)準(zhǔn)中的任何字符,而且其編碼中的第一個字節(jié)仍與ASCII相容,使得原來處理ASCII字符的軟件無須或只進(jìn)行少部分修改后,便可繼續(xù)使用。因此,它逐漸成為電子郵件、網(wǎng)頁及其他存儲或傳送文字的應(yīng)用中,優(yōu)先采用的編碼。

3、UTF-8 BOM

UTF-8 不需要 BOM 來表明字節(jié)順序,但可以用 BOM 來表明編碼方式。字符 “Zero Width No-Break Space” 的 UTF-8 編碼是 EF BB BF。所以如果接收者收到以 EF BB BF 開頭的字節(jié)流,就知道這是 UTF-8編碼了。Windows 就是使用 BOM 來標(biāo)記文本文件的編碼方式的。

4、CSV文件亂碼問題

類似WINDOWS自帶的記事本等軟件,在保存一個以UTF-8編碼的文件時,會在文件開始的地方插入UTF-8 BOM頭。記事本等編輯器通過它來識別這個文件是否以UTF-8編碼(當(dāng)然即便沒有UTF-8 BOM頭記事本也能通過其它方式正確識別UTF-8編碼)。

三、編碼解碼

在計算機(jī)發(fā)展初期,美國等少數(shù)國家最先給自己的語言設(shè)置了一套編碼,即ASCII。因?yàn)橛⒄Z只有26個英文字母及一些常見的符號即可,因此只需要一個字節(jié)的 7 位(即 128 個整數(shù))就能完全表示英文字符。

但隨著計算機(jī)的發(fā)展,歐洲一些國家也需要為自己的語言設(shè)置一套編碼,ASCII的128個字符不夠用了,因此就產(chǎn)生了第二套編碼類型 ISO-8859-1 ~ ISO-8859-15,其中使用最廣泛的是ISO-8859-1,ISO-8859-1使用了一個字節(jié)的 8 位,可以表示256個字符。為了避免亂碼問題,ISO-8859-1完全兼容ASCII,ISO-8859-1的前128位和ASCII完全一致,后128個字符才是ISO-8859-1自身新擴(kuò)展的字符編碼。

后來,中國也給漢語設(shè)置了一套編碼,提出了適合漢語的編碼集GB2312。GB2312包含了682個英文、字母等符號及常見的6763個簡體中文,我勒個去,中華上下五千年,博大精深啊。

再后來,為了將簡體中文和繁體中文兼容到字符集里,又發(fā)布了新的編碼集GBK。GBK實(shí)際是GB2312的擴(kuò)展,使用1個字節(jié)存儲ASCII中的字符,使用2個字節(jié)存儲一個中文漢字。

最后,為了給世界上的所有字符設(shè)置一套統(tǒng)一的編碼集,出臺了統(tǒng)一的字符集規(guī)范Unicode(國際標(biāo)準(zhǔn)字符集)。其中就包含最著名的UTF-8。

UTF-8是ASCII的超集,ASCII中每個字符的編碼與UTF-8是完全一致的,因此當(dāng)用UTF-8存儲漢字或其他字符時,可能會使用2個、3個或4個字節(jié)。

  • 1個字節(jié):英文,數(shù)字,回車符,ASCII中的常用符號+、-、*、/等;
  • 2個字節(jié):個別特殊符號;
  • 3個字節(jié):常見漢字,在GBK中存在的漢字;
  • 4個字節(jié):中日韓等超大字符集里面的漢字;

在java.nio.charset.Charset類中,提供了一些編碼及常用方法。

四、解決讀取“帶有BOM的UTF-8文件亂碼”問題

1、讀取文件編碼集

按照給定的字符集存儲文件時,在文件的最開頭的三個字節(jié)中就有可能存儲著編碼信息,所以,基本的原理就是只要讀出文件前三個字節(jié),判定這些字節(jié)的值,就可以得知其編碼的格式。其實(shí),如果項目運(yùn)行的平臺就是中文操作系統(tǒng),如果這些文本文件在項目內(nèi)產(chǎn)生,即開發(fā)人員可以控制文本的編碼格式。

2、用指定的編碼格式讀取文件流,寫入文件流

(1)讀取CSV文件

public static List<String[]> readCSVToListByUnicode(String filePath) {
        FileInputStream fis = null;
        UnicodeInputStream uin = null;
        InputStreamReader in= null;
        try {
            //logger.info("讀取文件"+filePath+"編碼集");
            List<String[]> list = new ArrayList<String[]>();
            //URL url = new URL(filePath);
            File f  = new File(filePath);
            fis = new FileInputStream(f);
            uin = new UnicodeInputStream(fis,enc);  //如果是本地將url.openStream -> new FileInputStream(f)
            enc = uin.getEncoding(); // check and skip possible BOM bytes
            if (enc == null){
                in = new InputStreamReader(uin);
            }else {
                in = new InputStreamReader(uin, enc);
            }
            long start = System.currentTimeMillis();
            //logger.info("讀取文件"+filePath+"查看耗時開始");
            BufferedReader reader = new BufferedReader(in);
            //BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream("D:/tags.txt"),"utf-8"));
            //String tmp =reader.readLine();

            String[] headtilte = reader.readLine().split(",");
            list.add(headtilte);
            String line = null;
            String[] itemArray = null;
            while ((line = reader.readLine()) != null) {
                itemArray = line.split(",");
                list.add(itemArray);
            }
            long end = System.currentTimeMillis();
            //logger.info("讀取文件"+filePath+"查看耗時="+(end-start)+"毫秒");
            return list;
        }catch (Exception e){
            logger.info("讀取文件"+filePath+",異常:", e);
            return null;
        }finally {
            try {
                if(in!=null){
                    in.close();
                }
                if(uin!=null){
                    uin.close();
                }
                if(fis!=null){
                    fis.close();
                }
            }catch (Exception e){
                logger.info("讀取文件"+filePath+",關(guān)閉流異常:", e);
            }
        }
    }

(2)獲取文件編碼集

package com.guor.demo.utils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.io.InputStream;
import java.io.PushbackInputStream;

public class UnicodeInputStream extends InputStream {

    private static final Logger logger = LoggerFactory.getLogger(UnicodeInputStream.class);

    PushbackInputStream internalIn;

    boolean isInited = false;

    String defaultEnc;

    String encoding;

    private static final int BOM_SIZE = 4;

    public UnicodeInputStream(InputStream in, String defaultEnc) {
        internalIn = new PushbackInputStream(in, BOM_SIZE);
        this.defaultEnc = defaultEnc;
    }

    public String getDefaultEncoding() {
        return defaultEnc;
    }

    public String getEncoding() {
        if (!isInited) {
            try {
                init();
            } catch (IOException ex) {
                IllegalStateException ise = new IllegalStateException("Init method failed.");
                ise.initCause(ise);
                throw ise;
            }
        }
        return encoding;
    }

    /**
     * Read-ahead four bytes and check for BOM marks. Extra bytes are
     * unread back to the stream, only BOM bytes are skipped.
     */
    protected void init() throws IOException {
        if (isInited) {
            return;
        }
        byte bom[] = new byte[BOM_SIZE];
        int n, unread;
        n = internalIn.read(bom, 0, bom.length);

        //logger.info("文件的前四個字符==="+bom[0]+","+bom[1]+","+bom[2]+","+bom[3]);

        if ( (bom[0] == (byte)0x00) && (bom[1] == (byte)0x00) &&
                (bom[2] == (byte)0xFE) && (bom[3] == (byte)0xFF) ) {
            encoding = "UTF-32BE";
            unread = n - 4;
        } else if ( (bom[0] == (byte)0xFF) && (bom[1] == (byte)0xFE) &&
                (bom[2] == (byte)0x00) && (bom[3] == (byte)0x00) ) {
            encoding = "UTF-32LE";
            unread = n - 4;
        } else if (  (bom[0] == (byte)0xEF) && (bom[1] == (byte)0xBB) &&
                (bom[2] == (byte)0xBF) ) {
            encoding = "UTF-8";
            unread = n - 3;
        } else if ( (bom[0] == (byte)0xFE) && (bom[1] == (byte)0xFF) ) {
            encoding = "UTF-16BE";
            unread = n - 2;
        } else if ( (bom[0] == (byte)0xFF) && (bom[1] == (byte)0xFE) ) {
            encoding = "UTF-16LE";
            unread = n - 2;
        } else {
            // Unicode BOM mark not found, unread all bytes
            encoding = defaultEnc;
            unread = n;
        }
        //System.out.println("read=" + n + ", unread=" + unread);
        if (unread > 0) {
            internalIn.unread(bom, (n - unread), unread);
        }
        isInited = true;
    }

    @Override
    public void close() throws IOException {
        //init();
        isInited = true;
        internalIn.close();
    }

    @Override
    public int read() throws IOException {
        //init();
        isInited = true;
        return internalIn.read();
    }
}

以上就是Java中常見的編碼集問題總結(jié)的詳細(xì)內(nèi)容,更多關(guān)于Java編碼集問題的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評論