java 如何存储 ucs4_Java中的字节,字符与编码,解码

ASCII编码

ASCII码主要是为了表示英文字符而设计的,ASCII码一共规定了128个字符的编码(0x00-0x7F),只占用了一个字节的后面7位,最前面的1位统一规定为0。

ISO-8859-1编码

为了扩展覆盖其他语言字符,ISO组织在ASCII码基础上又制定了一系列标准用来扩展ASCII编码,它们是ISO-8859-1~ISO-8859-15,其中ISO-8859-1应用得最广泛。

ISO-8859-1仍然是单字节编码,它总共能表示256个字符。ISO-8859-1向下兼容ASCII,其编码范围是0x00-0xFF,0x00-0x7F之间完全和ASCII一致。

因为ISO-8859-1编码范围使用了单字节内的所有空间,在支持ISO-8859-1的系统中传输和存储其他任何编码的字节流都不会被抛弃。换言之,把其他任何编码的字节流当作ISO-8859-1编码看待都没有问题。

Unicode,UCS2和UCS4

Unicode是为整合全世界的所有语言文字而诞生的。任何文字在Unicode中都对应一个值,这个值称为代码点(Code Point),常写成 U+XXXX的格式。而文字和代码点之间的对应关系就有UCS-2和UCS-4。

UCS-2:用两个字节来表示代码点,其取值范围为 U+0000~U+FFFF。

UCS-4:为了能表示更多的文字,人们又提出了UCS-4,即用四个字节表示代码点。它的范围为 U+00000000~U+7FFFFFFF,其中U+00000000~U+0000FFFF和UCS-2是一样的。

要注意,UCS-2和UCS-4只规定了代码点和文字之间的对应关系,并没有规定代码点在计算机中如何存储。规定存储方式的称为UTF(Unicode Transformation Format),其中应用较多的就是UTF-8和UTF-16了。

UTF-8,UTF-16,UTF-32

UTF-32是对应于UCS-4,不常用。

UTF-16是完全对应于UCS-2的,即把UCS-2规定的代码点通过Big Endian或Little Endian方式直接保存下来。所以UTF-16采用2个字节来存储Unicode。UTF-16也可以表示UCS-4的部分字符,所以UTF-16也采用4个字节来存储Unicode。

UTF-8为了节约存储空间和网络传输的流量UTF-8采用了一种变长技术,每个编码区域有不同的字码长度。不同类型的字符可以由1-6个字节组成。

Java采用UTF-16编码。在Java诞生的时候,UTF-16编码使用的更广泛,而且定长编码的形式也方便计算器处理。后来,随着互联网的流行和壮大,互联网的普及,强烈要求出现一种统一的编码方式,UTF-8编码才得以出现。

Big Endian,Little Endian与文本开头的标志

一个字符可能占用多个字节,比如字符0xABCD,如果存储为AB CD,则称为Big Endian;如果存储为 CD AB,则称为Little Endian。

要知道具体是哪种编码方式,需要判断文本开头的标志:

EF BB BF

UTF-8([EF BB BF]也称为BOM,可选项,一般Windows加,Linux不加)

FE FF

UTF-16/UCS-2, little endian(默认)

FF FE

UTF-16/UCS-2, big endian

FF FE 00 00

UTF-32/UCS-4, little endian(默认)

00 00 FE FF

UTF-32/UCS-4, big-endian

字节,字符转换及不同编码格式编码,解码

Java中字节是byte,占8位(1 byte = 8 bit),最高位是符号位,表示范围为-128~127。[代码1]

Java规定了字符的内码要用UTF-16编码,占16位(2 byte = 16 bit)表示范围为0~65535(没有符号位),用char表示(内码是程序内部使用的字符编码,特别是某种语言实现其char或String类型在内存里用的内部编码)。[代码2]

String.getBytes()是一个用于将String的内码转换为指定的外码的方法。无参数版使用平台的默认编码作为外码,有参数版使用参数指定的编码作为外码;将String的内容用外码编码好,结果放在一个新byte[]返回。[代码3]

字节流与字符流

InputStream为字节输入流的所有类的超类,Reader为读取字符流的抽象类。java读取文件的方式分为按字节流读取和按字符流读取,其中InputStream、Reader是这两种读取方式的超类。

其实字符流可以看做是一种包装流,它的底层还是采用字节流来读取字节,然后它使用指定的编码方式将读取字节解码为字符。在读取的时候字符读取每次是读取2个字节,字节流每次读取1个字节。[代码4]

Java web中的编码,解码

用户向服务器发送HTTP请求主要有以下两种方式:

1.URL方式直接访问

浏览器将会对URL的path和parameter(QueryString)进行编码操作。URL的编码规范规定浏览器将非ASCII字符按照某种编码格式编码成16进制数字然后将每个16进制表示的字节前加上"%"。但是对于不同的浏览器,版本,操作系统等环境都会导致编码结果不同。例Chrom使用UTF-8:[http://www.baidu.com/a我是?mparam=abc 我是谁] --> [http://www.baidu.com/a%E6%88%91?param=abc%20%E6%88%91%E6%98%AF%E8%B0%81]

服务器使用固定编码进行解码操作,如tomcat8以后默认编码格式是UTF-8;7之前的都是ISO-8859-1。也可以在/conf/server.xml中修改。

URL方式提交数据是很容易产生乱码问题的。关于一些解决乱码的方法,可参考http://cmsblogs.com/?p=1526,核心思想是直接通过JS一次或两次Encode,跳过浏览器的Encode。

2.表单提交(GET/POST)

表单形式一般都不会出现乱码问题。它采用的编码是由页面来决定的即charset。

1

2

3

4

5

Title

6

7

8

9

它可以通过JSP设定。

其中pageEncoding是jsp文件,而contentType的charset是指服务器发送给客户端时的内容编码。

流程大致为:JSP File ---[use pageEncoding/file.encoding]---> servlet.java ---[UTF-16]---> servlet.class ---[contentType/ISO-8859-1]---> Browser ---> HTML

[代码1]

1 public static voidmain(String[] args) {2 //十六进制表示-128,127

3 byte b1 = -0x80, b2 = 0x7F;4 System.out.println(b1 + ", " + b2); //output: -128, 1275 //八进制表示-128,127

6 byte b3 = -0200, b4 = 0177;7 System.out.println(b3 + ", " + b4); //output: -128, 1278 //十进制表示-128,127

9 byte b5 = -128, b6 = 127;10 System.out.println(b5 + ", " + b6); //output: -128, 12711 //也可以用0x00-0x7F的ASCII表示

12 byte b7 = '9', b8 = 'a';13 System.out.println(b7 + ", " + b8); //output: 57, 9714 //如果想把-128~-1转化成128~255可以用下面方法(负数存补码)

15 byte b9 = -0x00, b10 = -0x01, b11 = -0x80;16 System.out.println(Byte.toUnsignedInt(b9) + ", " + Byte.toUnsignedInt(b10) + ", " + Byte.toUnsignedInt(b11));//output: 0, 255, 128

17 }

[代码2]

1 public static voidmain(String[] args) {2 //char也可以八,十,十六用进制表示

3 char c1 = 0x61; //'a'

4 char c2 = 0x6211; //'我'

5 System.out.println(c1 + ", " + c2); //output: a, 我

6 }

[代码3]

1 public static void main(String[] args) throwsException {2 //对字符串用不同编码格式编码

3 String s1 = "abc 我是谁";4 char[] chars1 =s1.toCharArray();5 byte[] bytes1 = s1.getBytes("ISO-8859-1");6 byte[] bytes2 = s1.getBytes("GBK");7 byte[] bytes3 = s1.getBytes("UTF-8");8 byte[] bytes4 = s1.getBytes("UTF-16");9 printChart(chars1); //output: 61 62 63 20 6211 662F 8C01

10 printChart(bytes1); //output: 61 62 63 20 3F 3F 3F

11 printChart(bytes2); //output: 61 62 63 20 CE D2 CA C7 CB AD

12 printChart(bytes3); //output: 61 62 63 20 E6 88 91 E6 98 AF E8 B0 81

13 printChart(bytes4); //output: FE FF 00 61 00 62 00 63 00 20 62 11 66 2F 8C 0114 //对字符串用不同编码格式解码

15 System.out.println(Charset.defaultCharset().name()); //output: GBK (不同操作系统不同语言默认的系统编码格式有可能不同,LZ是中文Win7)

16 System.out.println(chars1); //output: abc 我是谁

17 System.out.println(new String(bytes1, "ISO-8859-1")); //output: abc ???(不可逆的乱码)

18 System.out.println(new String(bytes2)); //output: abc 我是谁

19 System.out.println(new String(bytes2, "UTF-8")); //output: abc ?????(乱码)

20 System.out.println(new String(bytes3, "UTF-8")); //output: abc 我是谁

21 System.out.println(new String(bytes4, "UTF-16")); //output: abc 我是谁

22 }

标志

a

b

c

(空格)

toCharArray[内码]

61

62

63

20

62 11

66 2F

8C 01

ISO-8859-1

61

62

63

20

3F

3F

3F

GBK

61

62

63

20

CE D2

CA C7

CB AD

UTF-8

61

62

63

20

E6 88 91

E6 98 AF

E8 B0 81

UTF-16

FE FF

00 61

00 62

00 63

00 20

62 11

66 2F

8C 01

[代码4]

1 public static void main(String[] args) throwsException {2 //读字节流

3 readByte("./conf/test2_GBK", "UTF-8"); //output: abc ?????(乱码)

4 readByte("./conf/test2_GBK", "GBK"); //output: abc 我是谁

5 readByte("./conf/test2_UTF-8", "UTF-8"); //output: abc 我是谁

6 readByte("./conf/test2_UTF-16", "UTF-16"); //output: abc 我是谁7 //读字符流

8 readChar("./conf/test2_GBK", "UTF-8"); //output: abc ?????(乱码)

9 readChar("./conf/test2_GBK", "GBK"); //output: abc 我是谁

10 readChar("./conf/test2_UTF-8", "UTF-8"); //output: abc 我是谁

11 readChar("./conf/test2_UTF-16", "UTF-16"); //output: abc 我是谁

12 }

[静态方法]

1 /**

2 * char转换为16进制3 */

4 public static void printChart(char[] chars) {5 for (int i = 0; i < chars.length; i++) {6 System.out.print(Integer.toHexString(chars[i]).toUpperCase() + " ");7 }8 System.out.println();9 }10

11 /**

12 * byte转换为16进制13 */

14 public static void printChart(byte[] bytes) {15 for (int i = 0; i < bytes.length; i++) {16 String hex = Integer.toHexString(bytes[i] & 0xFF);17 if (hex.length() == 1) {18 hex = '0' +hex;19 }20 System.out.print(hex.toUpperCase() + " ");21 }22 System.out.println();23 }24

25 /**

26 * 字节流读取27 */

28 private static voidreadByte(String fileName, String charset) {29 InputStream input = null;30 StringBuilder sb = newStringBuilder();31 try{32 input = new FileInputStream(newFile(fileName));33 byte[] bytes = new byte[64];34 //InputStream.read()每次都只读取一个字节,效率非常慢,所以使用read(byte[])做为一个缓冲数组

35 for (int n; (n = input.read(bytes)) != -1; ) {36 String str = new String(bytes, 0, n, charset);37 sb.append(str);38 }39 } catch(IOException e) {40 e.printStackTrace();41 } finally{42 try{43 input.close();44 } catch(IOException e) {45 e.printStackTrace();46 }47 }48 System.out.println(sb.toString());49 }50

51 /**

52 * 字符流读取53 */

54 private static voidreadChar(String fileName, String charset) {55 Reader input = null;56 StringBuilder sb = newStringBuilder();57 try{58 //FileReader继承了InputStreamReader,但并没有实现父类中带字符集参数的构造函数,所以FileReader只能按系统默认的字符集来解码59 //input = new FileReader(new File(fileName));

60 input = new InputStreamReader(newFileInputStream(fileName), charset);61 //FileReader.read()每次都只读取一个字符,效率非常慢,所以使用read(char[])做为一个缓冲数组

62 char[] chars = new char[64];63 for (int n; (n = input.read(chars)) != -1; ) {64 sb.append(chars, 0, n);65 }66 } catch(IOException e) {67 e.printStackTrace();68 } finally{69 try{70 input.close();71 } catch(IOException e) {72 e.printStackTrace();73 }74 }75 System.out.println(sb.toString());76 }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值