BIO和NIO(一)
BIO : 全名为,blocking IO,阻塞的IO,也是我们平时最为常用的字符流,字节流等。 NIO:全名为,Non-blocking IO或者称之为 new IO,是JDK 1.4 出现的。由于其是非阻塞的,效率高,越来越受到当前技术的欢迎。 1,BIO
BIO也称之为阻塞的IO。
当客户端发送一个数据到服务器,如果服务器一直没有数据返回,那么客户端中程序就一直在红色框中一直等待。
也称之为此时阻塞了。所以BIO也称之为阻塞的IO。且每一次数据的发送都是一个新的IO流。 2,BIO的分类
BIO主要有三大类:字节流、字符流,缓冲流。 下面本文就从这三类分别对BIO进行学习,NIO的内容会在下一篇文章中进行阐述。
2.1字节流
字节流:操作的都是字节数据,所以不管是音频,视频等都可以使用字节流进行操作。最为典型的就是关于视频文
件的拷贝操作。
2.1一次读写一个字节
代码示例:
public class Demo {
public static void main(String[] args) throws IOException {
//创建一个文件输入流,用来读取数据
FileInputStream fis = new FileInputStream("文件存放路径");
//创建一个文件输出流,用来写出数据
FileOutputStream fos = new FileOutputStream("文件拷贝路径");
int b;
在本案例中,使用的是最基本的读写方式,即:一个字节一个自己的读取。
如果要拷贝的文件过大,有100M,也就是100,000,000个字节。那么读写操作就需要循环1亿次,非常的慢。
如图所示:
由图可见,如果文件100M,那么从左到右的过程要进行1亿次,很慢。
2.2 利用字节数组读写
为了提高效率,那么我们可以一次读写多个字节,这些字节利用一个字节数组存放。
代码示例:
在本案例中,使用的是最利用字节数组读写方式,即:一次读写一个字节数组。
[AppleScript] 纯文本查看 复制代码 while((b = fis.read()) != ‐1){
fos.write(b);
} f
is.close();
fos.close();
}
}
[AppleScript] 纯文本查看 复制代码 public class Demo {
public static void main(String[] args) throws IOException {
//创建一个文件输入流,用来读取数据
FileInputStream fis = new FileInputStream("文件存放路径");
//创建一个文件输出流,用来写出数据
FileOutputStream fos = new FileOutputStream("文件拷贝路径");
int len;
//定义一个数组用来进行缓存
byte [] bys = new byte[8192];
while((len = fis.read(bys)) != ‐1){
fos.write(bys,0,len);
} f
is.close();
fos.close();
}
}
如果要拷贝的文件过大,有100M,也就是100,000,000个字节。那么此时根据定义的数组的大小就可以提高效率了。
如果文件100M,那么每次读写8192个字节,那么效率就提高了8192倍。
当读取的时候,将8192个字节存到这个数组中,当写出数据的时候,再将这个数组中的数据写到目的地文件中。
2.2字符流
字节流:操作的都是字符数据,因为音频,视频等文件在本地都是以字节的形式存储的,所以字符流不能操作这些
文件。字符流只能操作文本文件。
2.2.1字符流和字节流的区别
学到这里,有的同学不禁要疑问,字节流可以操作所有文件,当然也包含文本文件。字符流只能操作文本文件,那么字节流作用范围要比字节流广,那么以后字符流是不是就不用了呢?
其实不是的,因为在文本文件中,如果有中文,那么字节流就力不从心了。为什么呢?因为中文在计算机中不是以一个字节的形式存储的,GBK是两个字节,UTF-8是三个字节。所以如果使用字节流去读取中文,那么就会读到半个中文的尴尬。所以在操作文本文件的时候为了避免读到半个中文,那么建议使用字符流。
2.2.2字符流读取数据
使用字符流读取数据时,是按照字符读取的,代码示例:
代码中的ch就是依次表示读到的每一个字符,当然读到的是码表上的数字,再次转成字符后,就是文本文件中的字
符信息了。
2.2.3字符流写出数据
使用字符流写出数据也非常的方便,可以直接将一个字符串写到本地文件中。
代码示例:
2.3 缓冲流
2.3.1缓冲流的第一种方式
既然我们都知道利用字节流一次读写一个字节的方式非常的慢,那么编写Java源代码的大神怎么会不知道呢?所以
为了简化开发,不用我们自己定义缓冲数组,Java提供了缓冲流技术用于提高IO的效率。
代码示例:
[AppleScript] 纯文本查看 复制代码 public class Demo {
public static void main(String[] args) throws IOException {
//创建一个字符文件输入流
FileReader fr = new FileReader("文件路径");
int ch;
while((ch = fr.read())!= ‐1){
System.out.println((char)ch);
} f
r.close();
}
} p
ublic class Demo6 {
public static void main(String[] args) throws IOException {
FileWriter fw = new FileWriter("文件目的地");
fw.write("你好你好");
fw.close();
}
} p
ublic class Demo6 {
public static void main(String[] args) throws IOException {
//创建一个缓冲输入流
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("文件数据源"));
//创建一个缓冲输出流
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("文件目的地"));
int b;
while ((b = bis.read()) != ‐1) {
bos.write(b);
} b
is.close();
bos.close();
}
在缓冲流中,不管是读的还是写的都内置了一个长度为8192的数组。
所以,使用缓冲流可以提高效率。
如果所示:
所以缓冲流相当于将数据源中的数据一次读8192个字节,然后通过内存中的b一个一个的转到缓冲输出流的数组
中。再将缓冲输出流的数据写到目的地文件。
2.3.2缓冲流的第二种方式
为了提高缓冲流在内存中的转换速度,所以缓冲流在拷贝时还有第二种方式。
代码示例:
第二种方式又可以进一步提高第一种方式的不足。
}
[AppleScript] 纯文本查看 复制代码 public class Demo {
public static void main(String[] args) throws IOException {
//创建一个缓冲输入流
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("文件数据源"));
//创建一个缓冲输出流
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("文件目的地"));
int len;
byte [] bys = new byte[8192];
while ((len = bis.read(bys)) != ‐1) {
bos.write(bys,0,len);
} b
is.close();
bos.close();
}
}
3,四种拷贝方式的优劣
通过上面的学习,我们发现了如果想拷贝一个非文本文件,那么至少有四种方式:
一次读写一个字节
一次书写一个字节数组
缓冲流一次转换一个字节
缓冲流一次转换一个字节数组
那么这四种方式究竟哪种最快呢?
其实最快的是第二种方式,因为第二种方式由上面的图也可以清楚的发现,每次读和写操作的都是同一个数组,缓
冲流中读和写是两个不同的数组,中需要通过变量或者数组再次倒手。
总结
以后文本文件一律使用字符流。
非文本文件的操作如果需要效率最优,那么可以使用第二种方式
如果代码简单和效率兼顾,那么可以使用第三种和第四种。
|