java中的字符与字节

经常听大家谈论"java使用的是Unicode编码",真不知道他们是真知道,还人云亦云 !

首先说一下,java中class文件中使用的是utf-8编码,而在jvm运行时使用的是utf-16(如char)。

一、字节的形式写、读取文件

// 以字节流的形式写出
        FileOutputStream out = new FileOutputStream("text.txt");
        out.write("IamChinese".getBytes("utf-8"));
        out.write("我是中国人".getBytes("utf-8"));
        out.close();

// 以字节流的形式读出
        FileInputStream in = new FileInputStream("text.txt");
        byte[] array = new byte[25];
        in.read(array);
        System.out.println(new String(array, "utf-8"));
        in.close();

这里无论是 "IamChinese" 抑或  "我是中国人" ,暂时不管它在java中使用unicode编码时是使用什么字节表示的,我们只要关注逻辑上(到哪里他们都是一样字面值)它们是字符串,而这时我们想把这些字符串对应的utf-8编码后的字节流保存到文件中,所以在读取时我们可以按照保存的编码格式再反过来得到字符串字面值(因为英文字符使用utf-8编码时占用一个字节,而一个中文编码时占用3个字节,所有这里使用了长度为25的byte数组来保存从文件中读取的字节)。到这里时,你是不是认为这时的新new出的那个String它内部存放的是字符都是utf-8的格式呢,事实不然,已经强调过了,java中采用的是unicode编码,所以在new的时候,方法内部默默地使得存储的是unicode字符。

二、字符的形式写、读取文件

        // 以字符流的形式写出
        BufferedWriter out = new BufferedWriter(new OutputStreamWriter(
                new FileOutputStream("text.txt"), "utf-8"));
        out.write("IamChinese");
        out.write("我是中国人");
        out.close();

        // 以字符流的形式逐个读出
        BufferedReader in = new BufferedReader(new InputStreamReader(
                new FileInputStream("text.txt"), "utf-8"));
        int c;
        int i = 0;
        while ((c = in.read()) != -1) {
            System.out.println((char) c);
            System.out.println(c);
            i++;
        }
        System.out.println("一共有 " + i + " 个字符");
        in.close();

上面的代码在写出数据时和用字节流实现的是一样,只不过是使用api直接操作,而省略了自己的一步步构造字节的过程,但是奇怪的事情在于in.read()这条代码(api doc说明指出它是读出一个字符,也就是说不管你字符流是utf-8还是gbk编码,它肯定是返回一个字符),奇怪之处在于它的返回值是一个0-65535的整数,这可把我急坏了,这怎么可能呢?如果文件使用gbk编码,那么读取时使用的2个字节(0-65535)可以存下,但是当使用utf-8时一个中文三个字节啊,它是怎么转换的呢??!!其实并不是这样的,这时的read返回的整数只是这个字符对应的unicode编码时的双字节表示时的整数,并非字符存储时的具体编码对应的字节而后转换的整数。这也同时说明了在read的内部它已经将我们指定的编码格式的字符转换成了unicode编码,而在读取不同编码的文本文件时,只要我们正确指定编码方案,那么read方法会自己准取地读取一个字符(变现在文件里三个字节(utf-8的中文)或者一个字节(utf-8的英文字母)或者两个字符(gbk编码的中文)),然后将该字符根据unicode码表再翻译成一个2个字节的整数。

三、java中的中文字符编码

    char c=‘中‘;
    System.out.println((int)c);
    int a=20013;
    System.out.println((char)a);
    char cc=‘a‘;
    System.out.println((int)cc);
    System.out.println(Arrays.toString("a".getBytes("utf-8")));

四、注意事项

1. 无论什么格式的文件:字节流形式的(jpg、rmvb)或字符格式(txt),当它们被保存到磁盘上时都是字节形式,各种应用程序读取时(无论使用字符流、字节流)都是一个字节一个字节的读取,只是各种流api在使用装饰模式后,可能有了缓冲,封装字符(这时就要用到文件保存时使用的编码格式,如utf-8或者gbk)的操作,提供给用户的直接调用api就由它的名字“望文生义”,从而有了字符流。

2. 一切文件都可以使用字节流的形式读取。但是,对于字符文件,如果硬是使用字节流读取(且还需要解码出字符文字),那么就必须得事先知道该字符文件在保存时使用的是那种编码格式,否者我们得到的只是字节,当使用字节数组转换字符、字符串(如 new String(bytes,"utf-8");)时就会出错(而实际的编码字符编码使用的是gbk),这也是乱码的出现的本质原因。

3. 既然所有的文件都可以使用字节流的形式读取,那为何还有有字符流呢? 提供字符流的形式读取只是为我们方便的读取字符文件,为我们提供直接的读取字符的api(如readLine(),而不是每次都是用户自己读取字节,让后在自己根据编码格式生成字符。

4.什么叫java文本文件编码格式,class文件的编码格式,jvm运行时编码格式?它们之间有什么区别和影响吗?前两者都是文件保存到磁盘上时,将字符写成字节时使用的字符集类型,无论什么歌格式,只要读取时和写入时使用同一种字符集就没问题。而最后一者则是在内存中用以表示字符的字节形式。

5.java中无论什么字符都是两个字节,所以像英文字母这样的字符,在utf-8中只要一个字节,但是在unicode中就要再浪费一个字节存储。

6. 至于在utf-8的文件中,因为编码时针对不同类型的字符占用不同的字节数,字符流是怎么区分的呢?你可以参考utf-8编码规范,自然可以知道。

时间: 2024-10-10 13:05:09

java中的字符与字节的相关文章

由“Java中一个字符占两个字节”引起

起因 Java中一个字符占两个字节,这和C/C++稍有区别.在C/C++中我们可以通过sizeof运算符方便地知道某个变量类型或对象的大小,那在Java中又如何? 问题出现 Java为什么没有提供sizeof运算符? 要回答这个问题,我们可以从另一个角度来看,那就是为什么C/C++中提供sizeof运算符.这就让人忍不住想到C/C++和Java在内存管理上的区别. 在C中,内存分配和释放的任务交给了程序员,当我们尝试用malloc为某个对象分配一块堆内存时,一个无法逃避的问题是,这个即将被创建的

转:JAVA中各种字符编码类型转换

import java.io.UnsupportedEncodingException; /** * 转换字符串的编码 */public class ChangeCharset { /** 7位ASCII字符,也叫作ISO646-US.Unicode字符集的基本拉丁块 */ public static final String US_ASCII = "US-ASCII"; /** ISO 拉丁字母表 No.1,也叫作 ISO-LATIN-1 */ public static final

Java字符串中常用字符占用字节数

java中一个char型的数据(也就是一个字符)占两个字节.而Java中常用的字符包括数字.英文字母.英文符号.中文汉字.中文符号等,若在字符串中包含里面的多种字符,它们是否都占两个字符呢?答案是否定的. public class CharBytes { public static void main(String[] args) { String s1 = "1234567";// 7个数字字符 byte[] b1 = s1.getBytes(); System.out.printl

java中基本类型占用字节数

在Java中一共有8种基本数据类型,其中有4种整型,2种浮点类型,1种用于表示Unicode编码的字符单元的字符类型和1种用于表示真值的boolean类型.(一个字节等于8个bit) 1.整型类型              存储需求     bit数    取值范围      备注int                 4字节           4*8 short             2字节           2*8    -32768-32767long              8字

Java补缺补漏—字符、字节的概念及其区别

首先我们先看一下这个问题:“Java语言中字符串“学Java”所占的内存空间是几个字节?”,要回答这个问题我们就必须先要清楚什么是“字节”什么是“字符”. 字节(Byte):字节是通过网络传输信息(或在硬盘或内存中存储信息)的单位.字节是计算机信息技术用于计量存储容量和传输容量的一种计量单位,1个字节等于8位二进制,它是一 个8位的二进制数,是一个很具体的存储空间. 字符:人们使用的记号,抽象意义上的一个符号. '1', '中', 'a', '$', '¥', …… 谈到字符就不得不提ANSI及

java中基本类型占用字节数 (面试总问)

在移动开发中由于移动设备内存的局限性,往往需要考虑使用的数据类型所占用的字节数.下面简单介绍下Java中几种基本数据类型,以加深记忆. 在Java中一共有8种基本数据类型,其中有4种整型,2种浮点类型,1种用于表示Unicode编码的字符单元的字符类型和1种用于表示真值的boolean类型.(一个字节等于8个bit) 1.整型 类型              存储需求     bit数    取值范围      备注 int                 4字节           4*8 s

JAVA中替换字符的方法replace和replaceAll 区别

replace和replaceAll是JAVA中常用的替换字符的方法,它们的区别是:1)replace的参数是char和CharSequence,即可以支持字符的替换,也支持字符串的替换(CharSequence即字符串序列的意思,说白了也就是字符串);2)replaceAll的参数是regex,即基于规则表达式的替换,比如,可以通过replaceAll("\\d", "*")把一个字符串所有的数字字符都换成星号;相同点是都是全部替换,即把源字符串中的某一字符或字符

【Java编程】Java中的字符串匹配

在Java中,字符串的匹配可以使用下面两种方法: 1.使用正则表达式判断字符串匹配 2.使用Pattern类和Matcher类判断字符串匹配 正则表达式的字符串匹配: 正则表达式:定义一组字符串的一系列字符和符号,它由常量字符和特殊符号构成. 下面是正则表达式的一些预定义字符类,实际上是一些转义字符序列: 1.\d   代表任何数字 2.\D  代表任何非数字字符 3.\w  代表任何单字字符(如:字母.数字.下划线等等) 4.\W  代表任何非单字字符 5.\s   代表任何空白字符 6.\S

java中各种数据类型占用字节数

1字节(Byte)=8bit java的基本类型 类型 所占字节 byte 1 short 2 int 4 long 8 float 4 double 8 char 2 String中字母和汉字所占字符是不一样的,并且与编码有关 英文字母:A 字节数 编码 1 GB2312 1 GBK 1 GB18030 1 ISO-8859-1 1 UTF-8 4 UTF-16 2 UTF-16BE 2 UTF-16-LE 中文汉字:我 字节数 编码 1 GB2312 2 GBK 2 GB18030 1 IS