2011-05-13 636 views
8

我以爲在java中的字符是16位,如java doc建議。是不是弦的情況?我有一個存儲的對象到一個文件代碼:Java中的字符是1個字節還是2個字節?

public static void storeNormalObj(File outFile, Object obj) { 
    FileOutputStream fos = null; 
    ObjectOutputStream oos = null; 
    try { 
     fos = new FileOutputStream(outFile); 
     oos = new ObjectOutputStream(fos); 
     oos.writeObject(obj); 
     oos.flush(); 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } finally { 
     try { 
      oos.close(); 
      try { 
       fos.close(); 
      } catch (Exception e) { 
       e.printStackTrace(); 
      } 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
    } 
} 

基本上,我試圖存儲一個字符串"abcd"在提交"output",當我用一個編輯器打開output並刪除了無串的一部分,還剩下什麼只是字符串「abcd」,總共是4個字節。有人知道爲什麼通過使用ASCII而不是UNICODE來處理可以被ASCII支持的字符串,java是否會自動節省空間?謝謝

+3

只是一個想法:難道不是Java保存在UTF-8中嗎? – Rekin 2011-05-13 06:48:04

+0

是的,它確實存儲了字符串修改後的UTF-8 ... – MJB 2011-05-13 06:53:44

回答

7

(我認爲「無字符串部分」是指創建ObjectOutputStream時發出的字節。不想使用ObjectOutputStream,但我不知道你的要求。)

只是FYI,Unicode和UTF-8不是一回事。 Unicode是一個標準,它指定了哪些字符可用。 UTF-8是一種字符編碼,用於指定如何將這些字符以1和0進行物理編碼。 UTF-8可以使用1個字節的ASCII(< = 127)和最多4個字節來表示其他Unicode字符。

UTF-8是ASCII的超集。因此,即使您爲某個文件指定了UTF-8編碼,並且向其中寫入了「abcd」,它也只包含這四個字節:它們具有與UTF-8中相同的ASCII碼物理編碼。

你的方法使用的是ObjectOutputStream,它實際上與ASCII或UTF-8編碼有着明顯不同的編碼!如果仔細閱讀Javadoc,如果obj是一個字符串並且已經發生在流中,則後續對writeObject的調用將引發對前一個字符串的引用,可能導致在重複的字符串中寫入更少的字節。

如果您認真對待這一點,您應該花大量時間閱讀Unicode和字符編碼系統。作爲開始,Wikipedia有一篇關於Unicode的優秀文章。

+0

關於unicode字符串的內存表示的另一個重要的事情是unicode codepoint不總是適合16位字符。 – CodesInChaos 2011-05-13 08:04:02

+0

@CodeInChaos - 你能提供一些超過16位的場景嗎? – 2011-05-13 09:48:50

+0

任何不在基本平面中的字符都有大於2^16-1的碼點。所以UTF-16將它編碼成兩個16位字符。 http://en.wikipedia.org/wiki/UTF-16/UCS-2 – CodesInChaos 2011-05-13 10:01:48

2

是的,char只是在Java運行時環境的上下文中的Unicode。如果您希望使用16位編碼編寫它,請使用FileWriter

FileWriter outputStream = null; 

    try { 
     outputStream = new FileWriter("myfilename.dat"); 

     int c; 
     while ((c = inputStream.read()) != -1) { 
      outputStream.write(c); 
     } 
    } finally { 
     if (outputStream != null) { 
      outputStream.close(); 
     } 
    } 
+0

我不認爲你理解的點Pal-他問爲什麼輸出流寫單字節。我相信下面的答案是我的答案。 – MJB 2011-05-13 06:51:56

+1

@MJB - 不,編碼很重要。如果他使用16位編碼編寫,操作系統會考慮它併爲單個字符分配16位。儘管這取決於操作系統。 – 2011-05-13 07:04:32

+1

我不會建議使用'FileWriter',因爲它沒有辦法指定編碼,只有**支持默認編碼。 (不幸的是更詳細的)'新的OutputStreamWriter(新的FileOutputStream(文件),編碼)'是更好的選擇。 – 2011-05-13 07:30:53

1

如果看一下String的來源,它會注意到它調用DataOutput.writeUTF來編寫Strings。如果你讀到,你會發現它們被寫爲「修改的UTF-8」。細節很長,但如果你不使用非7位ascii,是的,它將需要一個字節。如果你想讓血淋淋的細節看看DataOutput.writeUTF()中的EXTREMELY long javadoc()

-1

那麼你期望16*4=64 bits = 8 bytes文件?超過UTF-8或ASCII編碼。一旦文件寫入文件。內存(根據空間)管理取決於操作系統。而你的代碼沒有控制權。

+0

這不是事實,你的代碼可以絕對控制輸出被編碼。 – sjr 2011-05-13 07:08:20

+0

我明白。但即使您指定了,操作系統也需要管理它所需的空間。 (請理解,我不反對操作系統會改變編碼) – 2011-05-13 07:12:16

+0

請參閱我對@PålBrattberg的回答的評論。 – 2011-05-13 07:13:23

0

您可能有興趣知道在Java Update 21性能版本及更高版本中有-XX:+UseCompressedStrings選項。這將允許字符串使用byte[]作爲不需要的字符串char[]

儘管Java Hotspot VM Options指南提示它可能默認處於打開狀態,但這可能只適用於性能發佈。如果我明確地打開它,它似乎只適用於我。

相關問題