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文件,复制到硬盘上的另外一个位置。1、什么方式读什么数据:文件的方式读非纯文本数据,所以使用字节输入流,操作的是文件,选用FileInputStream。
2、什么方式写数据:文件的方式写非纯文本数据,所以使用字节输出流,操作的是文件,选用FileOutputStream。
于是有如下代码:
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("关闭输出流异常");
}
}
}
}
那么,又如:要将键盘录入的数据,以文件的形式保存到硬盘。
1、什么方式读什么数据:字节数据,所以使用字节输入流,可是我们要以文本的形式存储,所以使用字节转字符的转换字符输入流,InputStreamReader
2、什么方式写数据:文件的方式写文本数据,所以使用字符输出流,操作的是文件,选用FileWriter。
于是有如下代码:
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("关闭输出流异常");
}
}
}
}