目录
3.1 FileInputStream和FileOutputStream
3.2 BufferedInputStream和BufferedOutputStream
4.1 InputStreamReader和OutputStreamWriter
4.2 BufferedReader和BufferedWriter
前言
Java的IO体系比较庞大,IO主要用于处理设备之间的数据传输,Java就是通过IO类来操作这些数据传输的。下面就简单的介绍下常用的Java IO相关类。
1、流的分类
1.1 什么是流?
流是一个比较抽象的概念,它表示的是数据传输的通道,例如我们将磁盘中的数据读到内存,然后经过处理后再将数据写入到磁盘,这个过程就用到了流的概念,即数据从磁盘流入内存,然后又从内存流出到磁盘。
1.2 按流向分类
输入流:程序可以读数据的流,例如:InputStream,Reader
输出流:程序可以写数据的流,例如:OutputStream,Writer
1.3 按数据传输单位分类
字节流:以字节为单位传输数据的流,例如:InputStream, OutputStream
字符流:以字符为单位传输数据的流,例如:Reader, Writer
1.4 按功能分类
节点流:用于直接操作设备的流,例如:FileInputStream,FileOutputStream
过滤流:对已存在流进行进行封装,使其可以高效的处理数据的流,例如:BufferedInputStream, BufferedOutputStream
2、字节流和字符流概述
字节流操作的是单个字节,一般用来操作二进制文件(例如:图片,视频,音频);字符流操作的是单个字符,单个字符不同的编码可能对于的字节不同,例如一般中文UTF-8编码占3个字节,GBK编码占2个字节,字符流一般操作文本文件。字节流和字符流的相关类比较多,IO的分类如下:
3、字节流
3.1 FileInputStream和FileOutputStream
FileInputStream 是从文件系统中的文件中读入数据,FileOutputStream是将数据写入到文件系统中的文件中去。类中相关方法就不列举了,有兴趣的查下JDK开发手册。示例如下:
public class FileIOStreamDemo {
public static void main(String[] args) {
try {
testFileIOStream();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 测试 FileInputStream和FileOutputStream
* 以下采用2种方式读写数据(2m大小的mp3格式文件)
* 1、每次从输入流中读取一个字节后就写入到输入流中(此种方式比较慢)
* 2、采用缓冲区的方式读取,每次将数据读进缓冲区中,当缓冲区满了之后再一次性写入(此种方式比较快)
* @throws IOException
*/
public static void testFileIOStream() throws IOException {
/*
* 也可以用FileInputStream fi = new FileInputStream("D:\\demo\\hhh.mp3");
* 因为FileInputStream构造函数中有一个可以接受字符串,底层是调用new File(path)的
*/
FileInputStream fi = new FileInputStream(new File("D:\\demo\\hhh.mp3"));
FileOutputStream fo = new FileOutputStream(new File("D:\\demo\\copyhhh.mp3"));
// 每读一个字节就写入(此种方式比较慢)
readWriteOneByte(fi, fo);
// 采用缓冲区的方式读写数据(此种方式效率高)
readWriteByBuffer(fi, fo);
//操作完成后记得关闭流
fi.close();
fo.close();
}
public static void readWriteOneByte(FileInputStream fi, FileOutputStream fo)
throws IOException {
long beginTime = System.currentTimeMillis();
int data = -1;
while ((data = fi.read()) != -1) {
fo.write(data);
}
long endTime = System.currentTimeMillis();
System.out.println("用时:"+(endTime-beginTime)+"毫秒");
}
public static void readWriteByBuffer(FileInputStream fi, FileOutputStream fo)
throws IOException {
long beginTime = System.currentTimeMillis();
// 读入1m的数据后一次性写入,缓冲区大小为1m
byte[] buf = new byte[1024*1024];
int len = -1;
while ((len = fi.read(buf)) != -1) {
fo.write(buf, 0, len);
}
long endTime = System.currentTimeMillis();
System.out.println("用时:"+(endTime-beginTime)+"毫秒");
}
}
上面代码运行结果分别为 用时:11740毫秒 和 用时:7毫秒
从上述结果中我们可以看到,采用缓冲区的方式读写数据效率要比一个字节一个字节读写的效率高。
3.2 BufferedInputStream和BufferedOutputStream
BufferedInputStream和BufferedOutputStream也是按字节读写数据的,不过它在流中加了缓冲区处理,所以效率会比不采用缓冲的FileInputStream和FileOutputStream快,在读数据时可以自定义缓冲区大小,也可以使用默认缓冲区,FileInputStream默认的缓冲区大小为8192(8k)。下面看下示例:
public static void testBufferIOStrean() throws IOException {
FileInputStream fi = new FileInputStream(new File("D:\\demo\\hhh.mp3"));
FileOutputStream fo = new FileOutputStream(new File("D:\\demo\\copyhhh.mp3"));
BufferedInputStream bi = new BufferedInputStream(fi);
BufferedOutputStream bo = new BufferedOutputStream(fo);
// 读取方式1 BufferedInputStream 中自带缓冲区(大小为8192 即8k)
int data = -1;
while ((data = bi.read()) != -1) {
bo.write(data);
}
// 读取方式2 自定义缓冲区大小读取
byte[] buf = new byte[8*1024];
int len = -1;
while ((len = bi.read(buf)) != -1) {
bo.write(buf, 0, len);
}
//操作完成后记得关闭流
bi.close();
bo.close();
}
4、字符流
4.1 InputStreamReader和OutputStreamWriter
InputStreamReader和OutputStreamWriter是按照字符处理数据的(其实底层实现也是按照字节读写的),读写方式和按字节方式读取数据相似。示例如下:
public static void testIOStreamRW() throws IOException {
FileInputStream fi = new FileInputStream("D:\\demo\\demo.txt");
FileOutputStream fo = new FileOutputStream("D:\\demo\\copyDemo.txt");
// 此处为了防止读写乱码,所以设置了字符编码(源文件为UTF-8格式)
InputStreamReader ir = new InputStreamReader(fi, "UTF-8");
OutputStreamWriter ow = new OutputStreamWriter(fo, ir.getEncoding());
// 方式1 每次读1个字符
int data = -1;
while ((data = ir.read()) != -1) {
ow.write(data);
}
// 方式2 每次读1024个字符
char[] ch = new char[1024];
int len = -1;
while ((data = ir.read(ch)) != -1) {
ow.write(ch, 0, len);
}
// 此处不需要关闭fi fo 因为ir.close()和ow.close()会将fi fo关闭
ir.close();
ow.close();
}
4.2 BufferedReader和BufferedWriter
BufferedReader和BufferedWriter采用了缓冲区,效率比较高,它的使用方式和按字节读取的方式相同,并且它支持按行读取。示例如下:
public static void testBufferedRW() throws IOException {
FileInputStream fi = new FileInputStream("D:\\demo\\demo.txt");
FileOutputStream fo = new FileOutputStream("D:\\demo\\copyDemo.txt");
// 此处为了防止读写乱码,所以设置了字符编码(源文件为UTF-8格式)
InputStreamReader ir = new InputStreamReader(fi, "UTF-8");
// 默认缓冲区大小为8k,当然可以自定义缓冲区大小new BufferedReader(ir, 1024*1024);
BufferedReader br = new BufferedReader(ir);
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(fo, ir.getEncoding()));
// 方式1 每次读1个字符
String str = null;
while ((str = br.readLine()) != null) {
bw.write(str);
// BufferedWriter不会自动将换行写入,所以此处需要写入换行
bw.newLine();
}
// 方式2 每次读1024个字符
char[] ch = new char[1024];
int len = -1;
while ((len = br.read(ch)) != -1) {
bw.write(ch, 0, len);
}
br.close();
bw.close();
}