java的IO流设计的很精巧,其中也涉及了设计模式中的装饰者模式。以此同时,由于IO流所涉及的类相对繁多,很多初学者往往会有或多或少的疑惑,甚至举步维艰,不知道该如何选取适合的流对象来完成相应的功能,很是头疼。看似简单,却不能正确把握要点。
那么,如何正确且快速掌握IO流呢?其实IO流也是有规律可寻的。
首先,先了解一些IO流的基本知识。
知识背景回顾:byte是字节,byte[]是字节数组,char是字符,char[]是字符数据,够详细了吧。接着记住这四个类,传说中的IO的奶爸奶妈。
用于处理字节的两个字节流:InputStream 与 OutputStream。
用于处理字符的两个字符流:Reader 与 Writer。
站在程序的角度,当程序要读入数据的时候,用InputStream字节输入流或者Reader字符输入流。同理,当程序要写出数据的时候,用OutputStream字节输出流或者Writer字符输出流。
那么,什么时候用字节流,什么时候用字符流呢?
字节byte,大小8位,字符char,大小16位,等于两个字节,字符是指计算机中使用的字母、数字、字和符号,包括:1、2、3、A、B、C、~!·#¥%……—*()——+等等。
所以知道了以上的知识后,只要是处理文本,汉字等内容的数据,都是使用有关于字符流的类,而当要处理音频文件、图片、歌曲、视频文件等内容的数据,使用字节流来处理。
当我们要开始着手写程序的时候。
1、思考什么方式读什么数据。
2、思考程序处理后的数据以什么方式写数据。
比如:要将硬盘上一个文本文件,复制到硬盘上的另外一个位置。
1、什么方式读什么数据:文件的方式读文本数据,所以使用字符输入流,操作的是文件,选用FileReader。
2、什么方式写数据:文件的方式写文本数据,所以使用字符输出流,操作的是文件,选用FileWriter。
于是有如下代码:
package com.java4fun; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; public class IOTest { public static void main(String[] args) { copyFile(); } private static void copyFile() { FileReader reader = null; FileWriter writer = null; try { // 建立读入文本,处理文件的字符流 reader = new FileReader("D:\\log.txt"); // 建立写出文本,处理文件的字符流 writer = new FileWriter("D:\\log_copy.txt"); // 将数据读入后存入字符数据中 char[] buf = new char[1024]; int len = 0; //当读到结尾时返回-1 while ((len = reader.read(buf)) != -1) { //将数据写出到新的文件 writer.write(buf,0,len); //刷新缓冲区,将数据写入文件中 writer.flush(); } } catch (FileNotFoundException e) { e.printStackTrace(); throw new RuntimeException("未找到要复制的文件"); } catch (IOException e) { e.printStackTrace(); throw new RuntimeException("建立复制文件异常"); } finally { try { if (reader != null) reader.close(); } catch (IOException e) { e.printStackTrace(); throw new RuntimeException("关闭输入流异常"); } try { if (writer != null) writer.close(); } catch (IOException e) { e.printStackTrace(); throw new RuntimeException("关闭输出流异常"); } } } }那么,比如:要将硬盘上一个mp3文件,复制到硬盘上的另外一个位置。
package com.java4fun; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; public class IOTest { public static void main(String[] args) { copyFile(); } private static void copyFile() { FileInputStream input = null; FileOutputStream output = null; try { // 建立读入非纯文本数据,处理文件的字节流 input = new FileInputStream("D:\\白狐.mp3"); // 建立写出非纯文本数据,处理文件的字节流 output = new FileOutputStream("D:\\狐白.mp3"); // 将数据读入后存入字节数组中 byte[] buf = new byte[1024]; int len = 0; //当读到结尾时返回-1 while ((len = input.read(buf)) != -1) { //将数据写出到新的文件 output.write(buf,0,len); //刷新缓冲区,将数据写入文件中 output.flush(); } } catch (FileNotFoundException e) { e.printStackTrace(); throw new RuntimeException("未找到要复制的文件"); } catch (IOException e) { e.printStackTrace(); throw new RuntimeException("建立复制文件异常"); } finally { try { if (input != null) input.close(); } catch (IOException e) { e.printStackTrace(); throw new RuntimeException("关闭输入流异常"); } try { if (output != null) output.close(); } catch (IOException e) { e.printStackTrace(); throw new RuntimeException("关闭输出流异常"); } } } }
package com.java4fun; import java.io.FileWriter; import java.io.IOException; import java.io.InputStreamReader; public class IOTest { public static void main(String[] args) { copyFile(); } private static void copyFile() { InputStreamReader isr = null; FileWriter fw = null; try { // 读进来的是字节,要将其处理成字符。所以建立字节转字符的转换字符流 isr = new InputStreamReader(System.in); // 将字符写出到文件中,建立文件输出字符流 fw = new FileWriter("D:\\content.txt"); char[] buf = new char[1024]; int len = 0; while ((len = isr.read(buf)) != -1) { //去掉回车换行 String content = new String(buf,0,len-2); //当输入end时,停止从键盘上获取字符。 if("end".equals(content)) { break; }else{ fw.write(content); //加入回车换行。 fw.write("\r\n"); fw.flush(); } } } catch (IOException e) { e.printStackTrace(); } finally { try { if (isr != null) isr.close(); } catch (IOException e) { e.printStackTrace(); } try { if (fw != null) fw.close(); } catch (IOException e) { e.printStackTrace(); } } } }
四个用于缓冲的类:
同样,缓冲字节流的BufferedInputStream,BufferedOutputStream.
同样,缓冲字符流的BufferedReader,BufferedWriter.
通常我们操作流的时候,效率极低,而且IO流提供给我们的缓冲类为什么提供了读取或操作数据很方便的方法。如BufferedReader的readLine()读取一行的方法,newLine()的方法等等。
缓冲流的使用也非常简单,构造缓冲流,接着将要缓冲的流传入即可。
例子如下,为上面的文本文件复制加入缓冲。
package com.java4fun; 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 IOTest { public static void main(String[] args) { copyFile(); } private static void copyFile() { BufferedReader br = null; BufferedWriter bw = null; try { // 缓冲流中传入用于读文本,处理文件的字符流 br = new BufferedReader(new FileReader("D:\\log.txt")); // 缓冲流中传入用于写出文本,处理文件的字符流 bw = new BufferedWriter(new FileWriter("D:\\log_copy.txt")); // 将数据读入后存入字符数据中 String line = null; while((line = br.readLine())!=null){ //写入一行文本数据,这个方法不会写入一行中的换行字符\r\n bw.write(line); //换行方法 bw.newLine(); bw.flush(); } } catch (FileNotFoundException e) { e.printStackTrace(); throw new RuntimeException("未找到要复制的文件"); } catch (IOException e) { e.printStackTrace(); throw new RuntimeException("建立复制文件异常"); } finally { try { if (br != null) //缓冲流的关闭实际是对作用流的关闭 br.close(); } catch (IOException e) { e.printStackTrace(); throw new RuntimeException("关闭输入流异常"); } try { if (bw != null) bw.close(); } catch (IOException e) { e.printStackTrace(); throw new RuntimeException("关闭输出流异常"); } } } }