Java专题 IO字符流 高效缓冲字符流 +文件拷贝案例,倒序写入另一文件,编码转化

IO字符流的使用

使用字节流写字符
可以使用,但是需要先把字符串转成字节数组,再存储到文件中,比较麻烦
使用字节流读取字符
如果是纯英文,可以一次读取一个字节
如果是纯中文,可以一次读取两个字节(GBK)
如果是纯中文,而且UTF-8的编码一次性读取三个字节
如果是中英文混杂,每次不知道读取多少个字节,因此无论字节数组准备多大,都会出现乱码

UTF-8中汉字占三个字节
GBK中汉字占2个字节
英文一般只占一个字节

	//IO字符流的使用
	System.out.println("a".getBytes().length);			//英文字符占用长度
	System.out.println("你".getBytes().length);			//汉字字符占用长度
	
	//IO字符流   每次读入的是一个字符
	//构造方法   用法基本上和字节流一致
	Reader reader = new FileReader("");
	Writer writer = new FileWriter("");
	reader.close();
	writer.close();

常用方法

	reader.read();							//也有如下方法
	writer.write(cbuf);		   //也可写入字符数组,格式为writer(char[] b,int start, int len);
											//从数组索引的第几个开始写,写几个
	Reader r1 = new FileReader("cc.txt");
	
	int i1;									//int i1;  不可换为char i1;	会出错
	while ((i1 = r1.read())!=-1) {			//读入一个字符 但输出使用的是i1 所以显示编码
		System.out.println(i1);				//要转为char 需要加入(char) 在i1前
	}
	r1.close();
	
	FileReader rf1 = new FileReader("cc.txt");
	
	char[] c1 = new char[1];			//定义字符数组接收
	int f1;
	while ((f1 = rf1.read(c1))!=-1) {
		System.out.print(new String(c1));	//输出的还是字符形式
	}
	rf1.close();
	

字符流拷贝

使用字符输入流读取信息,使用字符输出流写出信息,完成文件的使用字符流拷贝
没有必要使用字符流来进行拷贝,因为字符流会先将字节信息转成字符,读取到内存中,最后还要再把字符信息转成字节信息,写出到另外一个文件中。
中间做了两次没有意义的相反的操作,浪费了时间

	//字符流  拷贝
//	如果在读取到字符之后,需要人为的阅读和修改这个字符,那么就需要使用字符流
// 	如果只是简单的将信息进行转移或者拷贝,不供阅读,就不需要转成字符
	
	Reader r2 = new FileReader("cc.txt");
	Writer w2 = new FileWriter("d.txt");
	
	char[] c2 = new char[2];
	int i;
	while ((i = r2.read(c2))!=-1) {
		w2.write(c2,0,i);							//读多少写多少
	}
	
	r2.close();
	w2.close();
	

非纯文本文件不能使用字符流拷贝

当字符流读取到一个字节信息之后,需要查询编码表转成字符信息,如果是非纯文本文件,就可能读取到的字节信息无法转成对应的字符,因为这个字节信息在编码表中没有对应的字符,就只能使用英文的?来代替这个字符,这一步中,就对信息进行篡改。接下来将篡改之后的?字符信息,通过编码表转成字节信息(这一步虽然正确,但是已经没有意义),转成的字节信息,就和当初字符输入流读取的字节信息不一致了,写出到目标文件,就是错误信息

字符流小数组拷贝

不使用小数组进行拷贝,发现效率也比较高,因为在FileWriter中就有一个缓冲区数组,所以写出的效率就比较高。
在我们使用小数组之后,还可以提升读取字符的速度,最终也可以提升拷贝效率

	//不使用小数组的拷贝
	Reader r3 = new FileReader("cc.txt");			//16毫秒			6394字节(byte)
	Writer w3 = new FileWriter("d.txt");
	
	int i3;
	while ((i3 = r3.read())!=-1) {
		w3.write(i3);
	}
	
	r3.close();
	w3.close();
	
	//使用小数组拷贝
	Reader r4 = new FileReader("cc.txt");			//4毫秒			6394字节(byte)
	Writer w4 = new FileWriter("d.txt");
	
	char[] c4 = new char[5];
	int len4;
	while ((len4 = r4.read(c4))!=-1) {
		w4.write(c4,0,len4);					//使用多个读入时必须写成(变量 ,0,len)防错  
	}
	
	r4.close();
	w4.close();
	
	
		//其实提升也不小
	//不使用小数组进行拷贝,发现效率也比较高,因为在FileWriter中就有一个缓
	//冲区数组,所以写出的效率就比较高。
	//在我们使用小数组之后,还可以提升读取字符的速度,最终也可以提升拷贝效率

高效缓冲字符流

BufferedReader BufferedWriter

BufferedReader:每次调用read方法,只有第一次从磁盘中读取了8192个字符,存储到该类型对象的缓冲区数组中,将其中一个返回给调用者,再次调用read方法时,就不需要再访问磁盘,直接从缓冲区中拿一个出来即可,效率提升了很多。
BufferedWriter:每次调用write方法,不会直接将字符刷新到文件中,而是存储到字符数组中,等字符数组写满了,才一次性刷新到文件中,减少了和磁盘交互的次数,提升了效率

	Reader r5 = new FileReader("cc.txt");			//6毫秒           6394字节(byte)(B)
	BufferedReader br1 = new BufferedReader(r5);
	
	BufferedWriter bw1 = new BufferedWriter(new FileWriter("d.txt"));
	
	int i5;
	while ((i5 = br1.read())!=-1) {
		bw1.write(i5);
	}
	
	br1.close();
	bw1.close();
	

高效缓冲字符流的特有方法

	//高效缓冲字符流的特有方法

	br1.readLine();			//一次读入一行数据,到达末尾返回null
	bw1.newLine();			//为不同的操作系统提供不同的相对应的换行符
				//在一般的写入中可以在write方法中加 换行符来换行,Buffer中不能直接加入换行符
	
	BufferedReader br2 = new BufferedReader(new FileReader("cc.txt"));
	
	String s1;										//读入的为字符串用字符串接收
	while ((s1 = br2.readLine())!=null) {			//最后的结尾为null
		System.out.println(s1);
	}
	
	br2.close();

使用特有方法的拷贝

	//使用特有方法的拷贝
	BufferedReader bf3 = new BufferedReader(new FileReader("src/zG_review_practice/IO字"
			+ "符流.java"));
	BufferedWriter bw3 = new BufferedWriter(new FileWriter("d.txt"));
	
	String s3;
	while ((s3 = bf3.readLine())!=null) {
		bw3.write(s3);
	}
	bf3.close();
	bw3.close();
	

读入文件 以倒序写入另一个文件

	//读入文件  以倒序写入另一个文件
	BufferedReader br4 = new BufferedReader(new FileReader("cc.txt"));
	BufferedWriter bw4 = new BufferedWriter(new FileWriter("d.txt"));
	
	List<String> list = new ArrayList<>();
	
	String s4;
	while ((s4 = br4.readLine())!=null) {
		list.add(s4);
	}
	
	br4.close();			//关闭资源
	
	Collections.reverse(list);		//反转元素位置
	
	for (String string : list) {
		bw4.write(string);
		bw4.newLine();				//换行
	}
	
	bw4.close();

小知识

GBK:国标码,定义的是英文字符和中文字符。在GBK编码表中,英文字符占一个字节,中文字符占两个字节。
UTF-8:万国码,定义了全球所有语言的所有符号,定义了这些符号和数字的对应关系,英文字符使用一个字节进行存储,中文字符使用三个字节进行存储

OutputStreamWriter:字符流到字节流的桥梁,可以指定编码形式
构造方法:OutputStreamWriter(OutputStream os, String charSetName)
创建一个转换流对象,可以把将来方法中接收到的字符,通过指定的编码表
charSetName,编码成字节信息,再通过指定的字节流os,将字节信息写出
使用:直接使用Writer中的方法即可(该类是Writer的子类)
InputStreamReader:字节流到字符流的桥梁,可以指定编码形式
构造方法:InputStreamReader(InputStream is, String charSetName)
创建一个转换流对象,可以使用is这个指定的字节流,从磁盘中读取字节信息
,通过指定的编码表charSetName,将字节信息解码成字符信息,返回给调用者
使用:直接使用Reader类中的方法即可(该类是Reader的子类)
说明:
无论是读取的时候,还是写出的时候,都需要参考读取文件和目标文件的编码形式
读取源文件时,解码的形式必须和源文件的编码形式一致
写出到目标文件时,编码形式必须和目标文件的编码形式一致

字节流转成字符流,直接取字符,避免直接将字节转字符产生乱码的问题

	InputStreamReader isr= new InputStreamReader(new FileInputStream("src/com/ujiue/test/Demo09_流的转换.java"), "UTF-8");

	char[] c=new char[10];
	int len;
	while((len=isr.read(c))!=-1) {
		System.out.print(c);
	}
	
public static void du() throws IOException {		//每一次执行都对读的内容修改并重新写入
	Reader r1 = new FileReader("22.txt");			//这里的读入与写入不能同时定义否则会出错
	int i = r1.read();
	i-=1;
	Writer w1 = new FileWriter("22.txt");
	w1.write(i);
	
	r1.close();
	w1.close();
	
}

(仅作为Java 入门学习代码,实战中文件过大时不适合一次全部读取再一次全部写入)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值