Java IO和字符编码

一直以来被Java字符流、字节流搞混,今天就来做个了断:怎么只使用FileInputStream而不用Reader子类来输出汉字呢?

首先,Java的IO操作有两类(输入与输出流相对,这里只讲输入流):字节流InputStream和字符流Reader,InputStream和Reader都是抽象类。InputStream有基本的read()读取一个字节的方法和read(byte[])读取多个字节到byte数组的方法;Reader有read()读取两个字节即一个字符的方法和read(char[])读取多个字符到char数组的方法。

字节流InputStream又分为两类:节点流(常见的有FileInputStream)和过滤流(常见的有BufferedInputStream),都继承自InputStream,同理Reader也如此。过滤流BufferedInputStream只是对节点流的包装,源码如下:

public BufferedInputStream(InputStream in, int size) {
        super(in);
        if (size <= 0) {
            throw new IllegalArgumentException("Buffer size <= 0");
        }
        buf = new byte[size];
    }

当然,BufferedReader有readLine()读取一行的方法,使用更方便。

那么,回到开头,到底怎么用FileInputStream而不用Reader子类来输出汉字呢?方法如下:

首先在D盘下新建zoben.txt输入任何中文字符,保存时将编码改为Unicode,开始编写程序如下:

public static void main(String args[]) throws Exception {
		
<span style="white-space:pre">		</span>FileInputStream fis = new FileInputStream("D:\\zoben.txt");
		byte[] b = new byte[6];
		fis.read(b);
		//FileInputStream存放的是字节,要将其转为字符,必然涉及编码问题。
		String s = new String(b,"UTF-8");
		System.out.println(s);
		System.out.println(Charset.defaultCharset().displayName());

}


如上,b数组必须大于4,可能有同学疑惑Unicode不是用两个字节存储的吗?是的,但不要忘记,txt文件头几个字节是编码格式:

头2个字节如果是 ff fe 表示 unicode;
头3个字节如果是 ef bb bf 表示 utf-8;

因此,你把4改为6即可读取2个中文字符,改为8即可读取3个中文字符。

此时,如果你把txt文件另存为UTF-8格式,会显示中文乱码。UTF-8编码中文需要3个字符,并且如下所示,头三个字节是编码格式。因此,读取第一个字节需要将b数组设置为6,并且修改s=new String(b,"UTF-8")即可,当然,UTF-8可以不写,在我的机器上是默认编码,你可以使用System.out.println(Charset.defaultCharset().displayName())显示你的默认编码,b每增加3个字节多读取一个汉字。


对于FileReader来做个试验,当前我的zoben.txt是UTF-8编码的,如果我编程如下:

public static void main() throws Exception {
		FileReader fr = new FileReader(new File("D:\\zoben.txt"));
		//过滤第一个编码类型字符
		char c = (char)fr.read();
		//真正的第一个字符
		c = (char)fr.read();
		System.out.println(c);
		
}
那么,没问题,汉字正常输出。

如果我把zoben.txt编码改为Unicode,就出现乱码了。原因是:Java在内存中存储的总是Unicode编码。FileReader默认根据机器的缺省(此处为UTF-8,不是Unicode)编码进行读入,Java将其转为Unicode存储在内存中。Java在内存中操作是无所谓编码的,只是在字符输入和输出时就需要有编码的概念了。

到这里,你可能会说,指定FileReader输入的编码为Unicode不就行了吗?确实如此,然而FileReader并没有提供指定编码的功能。

那么该怎么办呢?也很简单,使用InputStreamReader就可以,如下:

public static void main() throws Exception {
		Reader r = new InputStreamReader(new FileInputStream("D:\\zoben.txt"),"Unicode");
		char c = (char)r.read();
		System.out.println(c);
}
如上,指定了将字节以Unicode的方式读入内存即可。

终于解决了这个问题。

总结:

1.Buffered只是过滤包装流

2.Java编码: 原编码(UTF-8或Unicode)>>Unicode(内存中)>>目标编码

3.BufferedReader有方便的readLine()方法

4.字节转为字符设计编码问题,如String s = new String(b,"UTF-8");




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值