个人理解:
在理解的字符流和字节流的区别后。要是想读取指定的编码格式的文件时,特别是不是默认的格式时,就需要转换流了,需要注意的是字符流是需要清除缓冲区的;当需要快速的进行读取时,则需要缓冲流。需要注意的是只有字符缓冲输入流 BufferedReader 才能按行读取数据!!!存在即是合理的,每个流都是有其优劣的,要特别注意好!
一、转换流:
1、OutputStreamWriter 是字符流通向字节流的桥梁:可使用指定的字符编码表,将要写入流中的字符编码成字节。它的作用的就是,将字符串按照指定的编码表转成字节,在使用字节流将这些字节写出去。
public class Demo01 { public static void main(String[] args) throws IOException { //明确目的地 FileOutputStream fos=new FileOutputStream("D:\\java\\a.txt"); //创建转换流对象 默认GBK OutputStreamWriter osw=new OutputStreamWriter(fos,"UTF-8"); //写入字符 osw.write("你好"); osw.flush(); //释放资源(功能流需要关,这里的fos被osw调用的,不需要咱关闭,由osw负责关闭---谁调用,谁负责关闭) osw.close(); }
其实在OutputStreamWriter流中维护自己的缓冲区,当我们调用OutputStreamWriter对象的write方法时,会拿着字符到指定的码表中进行查询,把查到的字符编码值转成字节数存放到OutputStreamWriter缓冲区中。然后再调用刷新功能,或者关闭流,或者缓冲区存满后会把缓冲区中的字节数据使用字节流写到指定的文件中。
2、InputStreamReader 是字节流通向字符流的桥梁:它使用指定的字符编码表读取字节并将其解码为字符。它使用的字符集可以由名称指定或显式给定,或者可以接受平台默认的字符集。
public class Demo02 { public static void main(String[] args) throws IOException { //明确数据源 FileInputStream fis=new FileInputStream("D:\\java\\a.txt"); //创建转换流对象 InputStreamReader isr=new InputStreamReader(fis,"UTF-8"); int len=0; char[] ch=new char[1024]; //开始读 while((len=isr.read(ch))!=-1){ System.out.println(new String(ch,0,len));//若是不写0和len就转为1024个字节,后面的为空格代替 } //释放资源 isr.close(); } }
3、转换流和子类区别:
OutputStreamWriter和InputStreamReader是字符和字节的桥梁:也可以称之为字符转换流。字符转换流原理:字节流+编码表。
FileWriter和FileReader:作为子类,仅作为操作字符文件的便捷类存在。当操作的字符文件,使用的是默认编码表时可以不用父类,而直接用子类就完成操作了,简化了代码。
InputStreamReader isr = new InputStreamReader(new FileInputStream("a.txt"));//默认字符集。
InputStreamReader isr = new InputStreamReader(new FileInputStream("a.txt"),"GBK");//指定GBK字符集。
FileReader fr = new FileReader("a.txt");
这三句代码的功能是一样的,其中第三句最为便捷。
注意:一旦要指定其他编码时,绝对不能用子类,必须使用字符转换流。什么时候用子类呢?
条件:
1、操作的是文件。2、使用默认编码。
总结:
字节--->字符 : 看不懂的--->看的懂的。 需要读。输入流。 InputStreamReader
字符--->字节 : 看的懂的--->看不懂的。 需要写。输出流。 OutputStreamWriter
public class Copy { public static void main(String[] args) throws IOException { //明确数据源 FileInputStream fis=new FileInputStream("D:\\java\\a.txt"); //创建字符输入转换流 InputStreamReader isr=new InputStreamReader(fis,"Utf-8"); //明确目的地 FileOutputStream fos=new FileOutputStream("D:\\java\\aa.txt"); //创建字符输出转换流 OutputStreamWriter osw=new OutputStreamWriter(fos,"UTF-8"); //5.开始复制 char[] ch=new char[1024]; int len=0; while((len=isr.read(ch))!=-1){ osw.write(ch,0,len); osw.flush(); } //释放资源 isr.close(); osw.close(); } }
二、缓冲流:
为了提高IO流的读写速度:
1、字节缓冲流:
public class Demo03 { public static void main(String[] args) throws IOException { Long start =System.currentTimeMillis(); //明确数据源 FileInputStream fis=new FileInputStream("E:\\shipin\\1.rar"); //创建字节输入缓冲流 BufferedInputStream bis=new BufferedInputStream(fis); //明确目的地 FileOutputStream fos=new FileOutputStream("D:\\java\\shipin.rar"); //创建字节输出缓冲流 BufferedOutputStream bos=new BufferedOutputStream(fos); byte[] bytes=new byte[1024]; int len=0; while((len=bis.read(bytes))!=-1){ bos.write(bytes,0,len); } long end=System.currentTimeMillis(); //释放资源 bis.close(); bos.close(); System.out.println("479MB的压缩包字节缓冲流复制的时间为"+(end-start)+"毫秒值!"); } }
2、字符缓冲流:
newLine() 根据当前的系统,写入一个换行符!
readLine() 读取一个文本行,包含该行内容的字符串,不包含任何行终止符,如果已到达流末尾,则返回 null
public class Copy { public static void main(String[] args) throws IOException { //明确数据源 FileReader fr=new FileReader("D:\\java\\hello.txt"); //创建字符输入缓冲流 BufferedReader br=new BufferedReader(fr); //明确目的地 FileWriter fw=new FileWriter("D:\\java\\nihao.txt"); BufferedWriter bw=new BufferedWriter(fw); String line=null; while((line=br.readLine())!=null){ bw.write(line); bw.newLine(); bw.flush(); } bw.close(); br.close(); } }
三、流的操作规则:
把IO流进行了规律的总结(四个明确):
1、 明确一:要操作的数据是数据源还是数据目的。
源:InputStream Reader
目的:OutputStream Writer
先根据需求明确要读,还是要写。
2、明确二:要操作的数据是字节还是文本呢?
源:
字节:InputStream
文本:Reader
目的:
字节:OutputStream
文本:Writer
已经明确到了具体的体系上。
3、明确三:明确数据所在的具体设备。
源设备:
硬盘:文件 File开头。
内存:数组,字符串。
键盘:System.in;
网络:Socket
目的设备:
硬盘:文件 File开头。
内存:数组,字符串。
屏幕:System.out
网络:Socket
完全可以明确具体要使用哪个流对象。
4、明确四:是否需要额外功能呢?
额外功能:
转换吗?转换流。InputStreamReader OutputStreamWriter
高效吗?缓冲区对象。BufferedXXX