2011-05-13 12 views
8

Pensé que los caracteres en Java son 16 bits como se sugiere en java doc. ¿No es el caso de las cadenas? Tengo un código que almacena un objeto en un archivo:¿Tiene un carácter 1 byte o 2 bytes en Java?

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(); 
     } 
    } 
} 

Básicamente, he tratado de almacenar una cadena "abcd" en presentar "output", cuando abrí output con un editor y eliminado la parte cadena ninguno, lo que queda es solo la cadena "abcd", que tiene 4 bytes en total. Alguien sabe por qué? ¿Java automáticamente ahorra espacio utilizando ASCII en lugar de UNICODE para cadenas que pueden ser compatibles con ASCII? Gracias

+3

Es sólo una idea: ¿no podría ser que Java ahorra en UTF-8? – Rekin

+0

Sí, exactamente - almacena Cadenas en UTF-8 modificado ... – MJB

Respuesta

7

(creo que por "ninguna parte de cadena" se refiere a los bytes que emite ObjectOutputStream cuando lo crea. No quiero usar ObjectOutputStream, pero no sé cuáles son sus requisitos.)

Solo FYI, Unicode y UTF-8 no son lo mismo. Unicode es un estándar que especifica, entre otras cosas, qué caracteres están disponibles. UTF-8 es una codificación de caracteres que especifica cómo estos caracteres se codificarán físicamente en 1s y 0s. UTF-8 puede usar 1 byte para ASCII (< = 127) y hasta 4 bytes para representar otros caracteres Unicode.

UTF-8 es un superconjunto estricto de ASCII. Por lo tanto, incluso si especifica una codificación UTF-8 para un archivo y le escribe "abcd", contendrá solo esos cuatro bytes: tienen la misma codificación física en ASCII que en UTF-8.

Su método utiliza ObjectOutputStream que en realidad tiene una codificación significativamente diferente de ASCII o UTF-8! Si usted lee el Javadoc con cuidado, si obj es una cadena y ya se ha producido en la corriente, las llamadas posteriores a writeObject causarán una referencia a la cadena anterior a ser emitida, que puede causar muchos menos bytes que se escriben en el caso de las cadenas repetidas .

Si usted es serio sobre la comprensión de esto, que realmente debería pasar una buena cantidad de tiempo leyendo acerca de Unicode y los sistemas de codificación de caracteres. Wikipedia tiene un excelente artículo sobre Unicode como punto de partida.

+0

Otra cosa importante acerca de la representación en memoria de las cadenas Unicode es que un punto de código Unicode no siempre cabe en un char de 16 bits. – CodesInChaos

+0

@CodeInChaos - ¿Puede proporcionar algunos escenarios en los que esto exceda 16bits? –

+0

Cualquier carácter que no esté en el plano básico tiene un punto de código mayor que 2^16-1. Así que UTF-16 lo codifica en dos caracteres de 16 bits. http://en.wikipedia.org/wiki/UTF-16/UCS-2 – CodesInChaos

2

Sí, el char sólo es Unicode en el contexto del entorno de ejecución de Java. Si desea escribir usando codificación de 16 bits, use un 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

No creo que entienda el punto en que Pal- está preguntando por qué un outputtream está escribiendo bytes individuales. Y la respuesta que creo es mi respuesta a continuación. – MJB

+1

@MJB - No, la codificación importa. Si escribe utilizando una codificación de 16 bits, el sistema operativo lo tendrá en cuenta y asignará 16 bits para un solo carácter. Aunque nuevamente depende del sistema operativo. –

+1

No recomendaría usar 'FileWriter', porque no tiene forma de especificar la codificación y ** solo ** admite la codificación predeterminada. El (desafortunadamente más prolijo) 'nuevo OutputStreamWriter (nuevo FileOutputStream (archivo), codificación)' es la mejor opción. –

1

Si nos fijamos en la fuente de la cadena, se notará que se llama DataOutput.writeUTF a escribir cadenas. Y si lo lee, descubrirá que está escrito como "UTF-8 modificado". Los detalles son largos, pero si no usa ascii no de 7 bits, sí, tomará un byte. Si desea que los detalles sangrientos miren el javadoc EXTREMADAMENTE largo en DataOutput.writeUTF()

-1

Entonces qué se puede esperar de un archivo 16*4=64 bits = 8 bytes? Más que codificación UTF-8 o ASCII. Una vez que el archivo se escribe en un archivo. La gestión de la memoria (en términos de espacio) depende del sistema operativo. Y su código no tiene control sobre él.

+0

Eso no es cierto, tu código puede controlar absolutamente cómo la salida está codificada. – sjr

+0

Yo entiendo. Pero incluso cuando lo especifique, le corresponde al sistema operativo administrar el espacio que necesita. (Por favor entender que, no estoy oponerse a que el sistema operativo va a cambiar la codificación) –

+0

ver mi comentario sobre la respuesta de @ Pål Brattberg .. –

0

Usted puede estar interesado en saber que hay una opción -XX:+UseCompressedStrings en Java versión de actualización 21 de rendimiento y después. Esto permite voluntad cadena a utilizar un byte[] para las cadenas que no necesitan un char[]

A pesar de la Java Hotspot VM Options guía que sugiere que puede ser activado de forma predeterminada, esto puede ser sólo para las versiones de rendimiento. Solo parece funcionar para mí si lo enciendo de forma explícita.

Cuestiones relacionadas