1. 程式人生 > 程式設計 >淺談java中位元組與字元的區別

淺談java中位元組與字元的區別

最近在看Java中的IO相關知識,發現對位元組和字元的理解還不夠。寫篇總結記錄一下。

一、位元組

所謂位元組(Byte),是計算機資料儲存的一種計量單位。一個二進位制位稱為位元(bit),8個位元組成一個位元組,也就是說一個位元組可以用於區分256個整數(0~255)。由此我們可以知道,位元組本是面向計算機資料儲存及傳輸的基本單位,後續的字元也就是以位元組為單位儲存的,不同編碼的字元佔用的位元組數不同。

那麼在Java中,除了儲存的意義外,Java還將位元組Byte作為一種基本資料型別,該資料型別在記憶體中佔用一個位元組,用於(-128~127)範圍內的整數

byte a = -128;
byte b = 127;

總的來說,位元組在Java中有兩種含義:

儲存的單位Java的資料型別,用於表示-128~127範圍的整數

二、字元

計算機底層儲存的是位元組,字元的設計則是用於展示符號。螢幕上顯示的各種文字,數字,符號等就是解碼的字元。所以我們說字元是用來顯示的符號,它將儲存的位元組轉換成人們看得懂的符號,因此字元的核心就是定義位元組與展示符號之間的關係,這種對映關係通常也叫做編碼。

2.1、編碼的由來

為什麼要編碼呢?前面我們知道資料都是以位元組為單位儲存在計算機中,位元組可以區分256個整數,最容易想到的就是將這256個整數定義為256種狀態並分別對應256個字元。但是人類符號太多了,256種是不夠的。所以人們想到將多個位元組合併起來表示人類語言符號,編碼的問題就轉化成了位元組的組合問題。

2.2、編碼的常見格式

如今有很多編碼格式,常見的如ASCII、ISO-8859-1、GB2312、GBK、UTF-8、UTF-16等等。

ASCII編碼是最基礎的編碼格式,標準的ASCII碼一共有128個,佔用位元組的低7位,將英語系語種的符號都能覆蓋住,但是總的來說能表示的字元還是非常有限。

ISO-8859-1編碼是ASCII編碼的一種擴充套件,它用了位元組的8位,能表示256種字元,且向下相容ASCII,包含了絕大多數的西歐符號。

GB2312是雙位元組編碼,意味著它使用兩個位元組來表示符號,包含有6763個漢字。

GBK是GB2312的一個擴充套件,也是雙位元組編碼,能夠表示21003個漢字,且向下相容GB2312。

...

編碼的規範越來越多,不同語言的國家都定義了自己的語言符號編碼標準,一時間編碼標準百花齊放,在網際網路的時代裡交流十分不便,不同編碼體系之間的資訊交流都需要採用不同的解碼方案,不然就會出現亂碼的現象。於是國際標準化組織ISO制定了一個能夠容納世界上所有文字和符號的字元編碼方案Unicode。Unicode是一個字符集,它規定了人類所有字元對應的二進位制數,至於這個二進位制數怎麼儲存則是由開發者來進行實現。其中比較流行的實現是UTF-8和UTF-16,還有一種UTF-32。

UTF-32編碼使用4個位元組,也就是32位二進位制儲存Unicode字元,效率高但是空間浪費。

UTF-8編碼是一種變長的編碼方式,它使用1~6個位元組來儲存,對於英語系的字元使用一個位元組,向下相容ASCII,對於漢字則使用兩個位元組,依次類推,這樣就能夠節省一定的空間。

UTF-16編碼是介於兩者之間的一種編碼方式。對於部分字符采用2個位元組,另一部分字符采用4個位元組。因此UTF-16無法相容ASCII。

在平時的使用中,UTF-8的使用還是比較多,就是由於它既能向下相容ASCII,還能夠在一定程度上節省空間。

2.3、Java IO流中的編碼和解碼

Java中是如何進行編碼和解碼的呢?我們知道,編碼/解碼的過程主要是發生在字元與位元組之間轉換的過程。在展示字元的時候,我們將記憶體中的位元組解碼成符號,在儲存或者傳輸檔案時,我們將字元編碼位位元組資料。解碼

解碼的過程是將位元組轉換為字元,也就是我們在讀取檔案或者網路資料的過程。

在java中,我們通過FileReader讀取檔案資料,FileReader繼承自InputStreamReader。在InputStreamReader中使用瞭解碼器StreamDecoder。

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

public class InputStreamReader extends Reader {
  // 解碼器,按照指定編碼方式將位元組轉換成字元
 private final StreamDecoder sd;

  // 通過dec指定解碼器使用的編碼方案
 public InputStreamReader(InputStream in,CharsetDecoder dec){
  super(in);
  if (dec == null)
   throw new NullPointerException("charset decoder");
  sd = StreamDecoder.forInputStreamReader(in,this,dec);
 }
  
  // 讀字元,以int形式(4位元組)返回字元
 public int read() throws IOException {
  return sd.read();
 }

}

通過上述InputStreamReader原始碼我們可以知道:

讀取輸入流時,通過StreamDecoder完成位元組到字元的轉換可以通過構造方法來設定編碼方案讀取的字元以int型資料返回,即4個位元組

另外,上述列舉只是原始碼的一部分,我們設定編碼方案有很多種形式,如在構造方法種傳入編碼方式的String型別名稱、傳入CharSet型別的字符集以及上述的CharsetDecoder型別的字元解碼方式。如果不傳入編碼方案,則預設為當前環境的編碼方案。編碼

與解碼類似,在儲存檔案或者寫入資料的時候,我們將字元轉換為位元組,寫入檔案或者網路。

在java種,我們通過FileWriter來寫入檔案,FileWriter繼承自OutputStreamWriter。在OutputStreamWriter種使用了編碼器StreamEncoder。

// OutputStreamWriter.java
import java.nio.charset.Charset;
import java.nio.charset.CharsetEncoder;
import sun.nio.cs.StreamEncoder;

public class OutputStreamWriter extends Writer {
 // 編碼器,按照指定編碼方式將字元轉換成位元組
 private final StreamEncoder se;

 // 通過enc指定編碼方案
 public OutputStreamWriter(OutputStream out,CharsetEncoder enc) {
  super(out);
  if (enc == null)
   throw new NullPointerException("charset encoder");
  se = StreamEncoder.forOutputStreamWriter(out,enc);
 }
 
 // 寫字元,寫入的字元以int型別傳入
 public void write(int c) throws IOException {
  se.write(c);
 }

通過原始碼我們可以知道:

  • 寫入輸出流時,通過StreamEncoder完成字元到位元組的轉換
  • 通過構造方法指定編碼方案
  • 寫入的字元都是int型別

到此這篇關於淺談java中位元組與字元的區別的文章就介紹到這了,更多相關java 位元組與字元 內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!