22-IO流-30-IO流(转换流的编码解码)

/*
 * 将一个字符串数据写入到一个文本文件中。
 * (1)明确源和目的:源是字符串,不需要流去关联它,目的需要流关联:OutStream,Writer
 * (2)是否为纯文本:源不需要流关联,只考虑目的,是纯文本,那么用Writer
 * (3)明确具体设备:源不管,目的是硬盘,那用File
 * 
 * FileWriter fw = new FileWriter("a.txt");
 * fw.write("你好");
 */

/*
 * 编码表小常识:
 * (1)电脑操作系统是什么版本,就用什么编码表,如简体中文版,那就用GBK表
 * 
 * (2)对于字符类型数据,java均用Unicode码表解析,但是字符串,java用的是当前电脑的默认码表GBK
 * 
 * (3)为方便各国文字编码,通常用2字节表示一个字符,但是对于'a'只需要一个字节,那用2字节如何表示?Unicode会在第一个字节位置
 * 用8个0表示,再用第二个字节表示字符a,由此发现Unicode码表较浪费空间
 * 
 * 所以导致同一个文字在不同码表中的查询结果也不同
 * 
 * (4)后来有了UTF-8码表,该码表特点是先判断当前字符占几个字节,占1个就用1个字节存,占2个就用2个字节存,占3个就用3个字节存,
 * 该码表给每一个字节头部加了一个编码头,从而出现2个字节装不下的情况。
 * 
 */

/**
 * 【新需求】将一个字符串按照指定编码表写入文本文件中。
 */

package demo;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;

public class Demo {

	public static void main(String[] args) throws IOException {

		readText_2();
	}

	public static void writeText_1() throws IOException {
		
		FileWriter fw = new FileWriter("gbk_1.txt");
//FileWriter就用默认编码表(当前系统是什么就用什么),不好改变
		fw.write("你好");
		fw.close();
//至此,在当前目录下新建gbk_1文本文件,其内容为:你好,大小为4字节(一个汉字=2字节)
	}
	
	
	
	public static void writeText_2() throws IOException {

/*
 * 对于新需求,发现FileWriter有局限,即编码表已经指定,查找API,发现转换流OutputStreamWriter有如下描述:
 * 			可使用指定的 charset 将要写入流中的字符编码成字节
 * 也就是说,该转换流可以指定任意编码表进行编码
 */
		OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("gbk_2.txt"));//默认编码表
		osw.write("你好");
		osw.close();//这三行代码运行效果同writeText_1

/*
 * FileOutpuStream是字节流和文件相关联
 * 转换流OutputStreamWriter的构造方法摘要中:
 * (1)OutputStreamWriter(OutputStream out):按照默认编码表(当前系统是什么,就用什么编码表)进行编码
 * (2)OutputStreamWriter(OutputStream out, String charsetName) :直接指定编码表名字即可,如GBK等
 * 第二个构造函数需要抛出异常:UnsupportedEncodingException,如果传进去一个“WC”,不支持,直接抛出异常
 */
		OutputStreamWriter osw1 = new OutputStreamWriter(new FileOutputStream("gbk_3.txt"),"GBK");
//FileOutputStream父类是OutputStream,所以这里传进去相当于多态。
		osw1.write("你好");
		osw1.close();//这三行代码运行效果同writeText_1
	
/*
 * OutputStreamWriter osw1 = new OutputStreamWriter(new FileOutputStream("gbk_3.txt"),"GBK");
 * FileWriter fw = new FileWriter("gbk_1.txt");
 * 
 * 这两句代码的功能相同。
 * FileWriter:其实就是转换流指定了本机默认码表的体现,而且这个转换流的子类对象,便于且只能操作文本文件(File)。
 * 				简单说:操作文件的字节流+本机默认的编码表
 * 				其局限就是:无法指定任意编码表,编码表是固定的。但这也是按照默认码表来操作文件的便捷类。
 * 
 * 如果需要指定编码表,那就必须用转换流完成。
 */
		
	}
	
	public static void writeText_3() throws IOException{//指定UTF-8码表进行编码
		
		OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("u8_1.txt"),"UTF-8");
		osw.write("你好");
		osw.close();
/*
 * 运行结果,在当前目录下生成一个名为u8_1的文本文件,其内容是:你好,大小是6字节而不是4字节。
 * 因为在UTF-8码表中,一个汉字=3字节,而GBK是一个汉字=2字节。
 */
	} 
	
	public static void readText_1() throws IOException {
		
		FileReader fr = new FileReader("gbk_1.txt");
		char[] buf = new char[1024];
		int len = fr.read(buf);
		String str = new String(buf,0,len);
		System.out.println(str);
		
		fr.close();
//成功读取gbk_1中的内容你好到控制台上,但是FileReader码表已经固定,是GBK,所以这几行代码读不了u8_1.txt
	}
	

	public static void readText_2() throws IOException {
//读取指定编码表的文本文件,FileReader已经不管用,需要转换流来完成
		InputStreamReader isr = new InputStreamReader(new FileInputStream("u8_1.txt"),"UTF-8");
//FileInputStream是用字节流读取文本文件,然后传给转换流InputStreamReader,因为转换流可以指定任意码表进行解析
		
		char[] buf = new char[1024];
		int len = isr.read(buf);
		String str = new String(buf,0,len);
		System.out.println(str);
		
		isr.close();
//成功读取用UTF-8编码的文本文件u8_1中内容:你好
//【注意】只要读取出看不懂的乱码,八成是编码表错误。
	}
}

/**
 * 重新审视新需求:
 * 既然需求中已经明确了指定编码表的动作,那就不可以用FileWriter,因为FileWriter
 * 内部是使用默认的本地码表,只能使用其父类转换流OutputStreamWriter,该转换流
 * 接收一个字节输出流对象,既然是操作文件,那么该对象应该是FileOutputStream
 * 
 * 代码如下:
 * OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("u8_1.txt"),"UTF-8"));
 * 
 * 高效:
 * BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(new FileOutputStrem("u8_1.txt"),"UTF-8"));
 */

/**
 * 什么时候使用转换流?
 * 1.源或者目的对应的设备是字节流,但是操作的却是文本数据,可以使用转换作为桥梁,
 * 提高对文本操作的便捷。
 * 2.一旦操作文本涉及到具体的指定编码表,必须使用转换流。
 */
























评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值