java程序员从笨鸟到菜鸟之(三十六)IO流之字符流

上一篇我们提到过,用字节流读取(文本文件)汉字打印在控制台上,会出现乱码,为解决这个问题引入了字符流

字符流是建立在字节流的基础上,能够提供字符层次的编码和解码

编码:将字符数据转换为字节数据(输入流--读数据);解码:将字节数据转换为字符数据(输出流--写数据)

类比:参考字符串的编码和解码

现在用字符流来读取处理不会出现乱码,是因为读取的不再是单个字节,而是能代表字符的多个字节,打印在控制台时,会通过编码表找到对应的字符。

注意1:默认采用Unicode编码,即在java里一个字符是由2个字节组成,所以对应的是0-65535之间(一个字节--0-255之间),会将指定格式的字符(对应的字节)转换为Unicode字符存储

注意2:指定的输入流的编码格式必须与要读的文本文件的编码格式一致

Reader和Writer类---抽象类----与编码方式有关类

 字符输入流读数据的方式:
   public int read():一次读取一个字符
   public int read(char[] chs):一次读取一个字符数组

 字符输出流写数据的方法:
   public void write(int c):写单个字符
   public void write(char[] cbuf):写一个字符数组
   public abstract void write(char[] cbuf,int off,int len):写入字符数组的一部分
   public void write(String str):写字符串
   public void write(String str, int off,int len):写字符串的一部分

转换流----字符流与字节流的桥梁----处理流

InputStreamReader(InputStream in):字符转换输入流

说明:读取一个字符,实际上读取的是该字符在此编码下(自己设置编码方式)对应的字节,然后转换为java平台默认的Unicodeb编码格式的字节,然后为该字符分配Unicodeb编码格式对应字节的内存空间。

注意:那么计算机是如何识别字符的?打印在控制台不会出现乱码?通过编码表(由字符及其对应数值组成的一张表)来唯一识别字符
OutputStreamWriter(Outputstream out):字符转换输出流

说明:对于每一个写入的字符,都会把它转换成指定的字符编码或者默认的方式,也即向输出流写入对应字符编码的字节

注意:从转换流得到的字符流,它读取的字符必须在编码表可以查到,否则会出现乱码,对于像图片、视频这样的文件不适宜用字符流来处理

实例1   一次读取一个字符

package 测试2;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;

/**
 * 字符输入流读数据的方式:
 *    public int read():一次读取一个字符		
 */
public class InputStreamReaderDemo {
	
	public static void main(String[] args) throws IOException {
		
		//1)创建字符输入流对象
		InputStreamReader isr = new InputStreamReader(new FileInputStream(
				"a.txt"));
		
		//2)方式1:一次读取一个字符
		/*
		 * 说明:好----Unicode编码:89(高八位)、125(低八位)
		 * 对应的Int值为22909
		 */
		int ch = 0 ;//read()返回值--每个字符对应的Unicode编码对应的字节的Int值
		while((ch=isr.read())!=-1){
		    System.out.print(ch);
		    System.out.print((char)ch);
		}
		//释放资源
		isr.close() ;
	}
	
}

实例2   一次读取一个字符数组

package 测试2;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;

/**
 * 字符输入流读数据的方式:
 * public int read(char[] chs):一次读取一个字符数组
 * 
 */
public class InputStreamReaderDemo {
	
	public static void main(String[] args) throws IOException {
		
		//1)创建字符输入流对象
		InputStreamReader isr = new InputStreamReader(new FileInputStream(
				"a.txt"));
		
		//2)方式2:一次读取一个字符数组
		char[] chs = new char[1024] ;//字符数组缓冲区
		int len = 0 ;//字符缓冲区中读取字符的实际个数
		while((len=isr.read(chs))!=-1){
			System.out.println(new String(chs, 0, len));
		}
		/*
		 * 说明:当文本中的字符数超过1024个时,
		 * 比如说1025个,那么下次实际读取的字符数是一个
		 * 为了避免打印空白等情况采用了String(chs, 0, len)的形式
		 * 打印字符缓冲区中真正的字符数
		 */
		
		//释放资源
		isr.close() ;
	}
	
}

实例3  一次写入一个字符(文件复制)

package 测试2;

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

public class InputStreamReaderDemo {
	
	public static void main(String[] args) throws IOException {
		
		//1)创建字符输入流、输出流对象
		InputStreamReader isr = new InputStreamReader(new FileInputStream(
				"a.txt"));
		OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(
				"b.txt"));
		
		//2)方式1:一次读取一个字符,写入一个字符
		int ch = 0 ;//
		while((ch=isr.read())!=-1){
			osw.write(ch);//写入字符
		}
		//释放资源
		isr.close() ;
		osw.close();
	}
	
}

实例4  一次写入一个字符数组(文件复制)

package 测试2;

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

public class InputStreamReaderDemo {
	
	public static void main(String[] args) throws IOException {
		
		//1)创建字符输入流对象
		InputStreamReader isr = new InputStreamReader(new FileInputStream(
				"a.txt"));
		OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(
				"b.txt"));
		
		//2)方式2:一次写入一个字符数组
		char[] chs = new char[1024] ;//字符数组缓冲区
		int len = 0 ;//字符缓冲区中读取字符的实际个数
		while((len=isr.read(chs))!=-1){
			osw.write(chs, 0, len);
			
		}
		
		//释放资源
		isr.close() ;
		osw.close();
	}
	
}

注意:如果不采用平台默认的编码格式,例如采用utf-8的编码格式,会发现复制文件后,打开文件会出现乱码(不影响我们通过读取识别)

原因:就是系统的编码和程序的编码采用了不同的编码格式

使用字符转换流进行操作数据的时候:字节流+编码格式(默认GBK),在书写代码名称非常长,Java提供了中更简单的类--便捷类

说明:便捷类是InputStreamReader和OutputStreamWriter的子类

FileWrite和FileReader类

特点(局限性):只能按照本地平台的字符编码(GBK),不能用户指定字符编码类型

实例5

package org.westos_09;

import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

public class FileReaderDemo {
	
	public static void main(String[] args) throws IOException {
		
		
		//1)封装数据源和目的地
		FileReader fr = new FileReader("a.txt") ;
		FileWriter fw = new FileWriter("b.txt") ;
		
		//一次读取一个字符数组
		char[] chs = new char[1024] ;
		int len = 0 ;
		while((len=fr.read(chs))!=-1){
			fw.write(chs, 0, len) ;
			fw.flush() ;
		}
		
		//关闭资源
		fw.close() ;
		fr.close() ;
	}
}

由于便捷类的性能达不到人们的需求,为了提高读写速度,Java就提供了一个字符缓冲流的类

   BufferedReader:字符缓冲输入流
   BufferedWriter:字符缓冲输出流
  将文本写入字符输出流,缓冲各个字符,从而提供单个字符、数组和字符串的高效写入。 
   通过构造方式可以指定缓冲区的大小,或者接受默认的大小

                常见读取方式:读取字节、读取字节数组
  构造方式:
  public BufferedWriter(Writer out):创建默认缓冲区大小的一个字符缓冲输出流

                关于字符缓冲输入流的特有功能:
                BufferedWriter:
   public void newLine():写入一个换行符号(等价==“\r\n”)
                BufferReader:
   public String readLine():一次读取一行(内容,字符串)

实例6  缓冲区读写

package org.westos_10;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

public class BufferedDemo {
	
	public static void main(String[] args) throws IOException {
		
		write();

		read();
	}

	private static void read() throws FileNotFoundException, IOException {
		
		//代码重复度高,使用循环改进
		String line = null ;
		while((line=br.readLine())!=null){
			System.out.println(line);
		}
		//释放资源
		br.close() ;
	}

	private static void write() throws IOException {
		//写数据
		//创建一个字符缓冲输出流对象
		BufferedWriter bw = new BufferedWriter(new FileWriter("bw2.txt")) ;
		
		//写数据
		for(int x = 0 ; x <10 ; x ++){
			bw.write("hello"+x) ;
			//没有使用这个方法之前:使用写入换行符号
			//bw.write("\r\n") ;
			//使用特有功能
			bw.newLine() ;			
			//刷新该流
			bw.flush() ;//必须刷新!!!
		}
		
		//释放资源
		bw.close() ;
	}
}

字符缓冲区流作用机理:由于带有缓冲区把一批数据写入到缓冲区内,当缓冲区满的时候,才把缓冲区的数据写入到字符缓冲流中

好处:避免每次都执行物理写操作,从而提高了I/O操作的效率

缺点:字符缓冲区的数据不满,会一直等待,如果不刷新就无法从缓冲区把数据写入到文件中

因此必须强制刷新

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值