2011-05-13 59 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指南提示它可能默认处于打开状态,但这可能只适用于性能发布。如果我明确地打开它,它似乎只适用于我。

相关问题