21 Java学习之字节流(InputStream和OutPutStream)

一.流的分类

1、从功能上:输入流、输出流

2、从结构上:字节流、字符流

3、从来源上:节点流、过滤流

  其中InputStream/OutputStream是为字节流而设计的,Reader/Writer是为字符流而设计的。处理字节或者二进制对象使用字节流,处理字符或者字符串使用字符流。

        在最底层,所有的输入/输出都是字节形式的,基于字符的流只在处理字符的时候提供方便有效的方法。

  节点流是从特定的地方读写的流,例如磁盘或者内存空间,也就是这种流是直接对接目标的。

  过滤流是使用节点流作为输入输出的,就是在节点流的基础上进行包装,新增一些特定的功能。

二. 什么是输入流和输出流?

        输入和输出流的概念其实都是针对内存(note:或者直接理解为我们的程序)说的。比如:我们常用来打印到控制台的命令System.out.println()它就是out,对于内存来说,把字符串打印到屏幕上就是从内存流向了屏幕的控制台;而等待用户输入命令确实System.in就是从键盘将字符输入到内存中。

因此:  从内存出:out (输出流)             进入到内存:in(输入流)

note:因为从内存到屏幕,就是写文件的流向;从硬盘到内存就是读文件的流向。

       如果时网络访问中,我们请求访问网页就是in,因为我们访问页面的时候时需要抓取该页面的一个html文件,因此是从网络到内存的流向;倘若有一个登陆页面,那么就是从内存到服务器了,因为需要从内存写数据到登陆界面,即out.

 三. InputStream

       其中有底色标注的为节点流,无底色标注的为过滤流,其中FilterInputStream在JDK中的定义为:包含其他一些输入流,它将这些流用作其基本数据源,可以直接传输数据或提供一些额外的功能,这个类本身并不经常被我们使用,常用的是它的子类。(note:上面InputStream的实现类没有例完,只是常用的)

定义了字节输入模式的抽象类,该类提供了三个重载的read方法:

我们可以看到,三个read方法中,其中有一个是抽象的。那在这里思考这样一个问题:为什么只有第一个是抽象的, 其他两个是具体的?

因为后面两个方法内部最终会去调用第一个方法,所以在InputStream派生类中只需要重写第一个方法就可以了。在这里可以看到第一个read方法是与具体的I/O设备相关的,需要子类去实现。

 1. 常用的字节输入流

  • InputStream  
  • FileInputStream
  • BufferedInputStream (BufferedInputStream不是InputStream的直接实现子类,是FilterInputStream的子类)

它们的区别与用途:

(1)InputStream:是抽象基类。其中定义了几个特别常用的方法,比如read和close方法。

(2)FileInputStream:主要用来操作文件的输入流。

(3)BufferedInputStream:一般读取是从硬盘里面读取数据;而带有缓冲区之后,BufferedInputStream是提前将数据封装到了内存中,因此内存中操作数据会更快,从而拥有比非缓冲区更高的效率。

2. 对写数据的逻辑顺序

(1)open a stream

(2)while more information

(3)read/wirte information

(4)close the stream

3. FileInputStream用法

 1 package com.test.a;
 2 
 3 import java.io.FileInputStream;
 4 import java.io.IOException;
 5 import java.io.InputStream;
 6 
 7 public class Test {
 8     public static void main(String args[]) throws IOException {
 9         InputStream is = new FileInputStream("C:\\Users\\hermioner\\Desktop\\test.txt");
10         int length = 0;
11         byte[] buffer = new byte[20];
12         StringBuffer stringBuffer = new StringBuffer();
13         while (-1 != (length = is.read(buffer, 0, 20))) {//一个中文字符占两个字节
14             stringBuffer.append(new String(buffer, 0, length, "GBK"));// WINDOWS中用ANSI代表,
15             System.out.println(stringBuffer);
16         }
17         System.out.println(stringBuffer);
18         is.close();
19 
20     }
21 }
22 
23 
24 /**
25  * 1.创建一个文件输入流 is
26  * 2.创建一个字节数组,用它来存放每次读取到内存中的内容,最多读取20个字节
27  * 3.必须要加入GBK,否则会乱码。
28  * 4.读完以后就关闭流is
29  * 
30  * */
View Code
1 输出:
2 
3 
4 少年强则国强,国强少
5 少年强则国强,国强少年则更强
6 少年强则国强,国强少年则更强
View Code

test.txt文件中的内容是:

少年强则国强,国强少年则更强     (note:以ANSI格式保存的)

4.BufferedInputStream用法

 1 package com.test.a;
 2 
 3 import java.io.BufferedInputStream;
 4 import java.io.FileInputStream;
 5 import java.io.IOException;
 6 
 7 public class Test {
 8     public static void main(String args[]) throws IOException {
 9         FileInputStream fileInputStream=new FileInputStream("C:\\Users\\hermioner\\Desktop\\test.txt");
10         BufferedInputStream bufferedInputStream=new BufferedInputStream(fileInputStream);
11         byte buffer[]=new byte[20];
12         int len=0;
13         while((len=bufferedInputStream.read(buffer))!=-1) {
14             System.out.println(new String(buffer,0,len,"GBK"));
15         }
16         
17         bufferedInputStream.close();
18         fileInputStream.close();
19 
20     }
21 }
22 
23 
24 少年强则国强,国强少
25 年则更强
View Code

5. 为什么需要BufferedInputStream?

BufferedInputStreamBufferedOutputStream这两个类分别是FilterInputStreamFilterOutputStream的子类,作为装饰器子类,使用它们可以防止每次读取/发送数据时进行实际的写操作,代表着使用缓冲区。

我们有必要知道不带缓冲的操作,每读一个字节就要写入一个字节,由于涉及磁盘的IO操作相比内存的操作要慢很多,所以不带缓冲的流效率很低。带缓冲的流,可以一次读很多字节,但不向磁盘中写入,只是先放到内存里。等凑够了缓冲区大小的时候一次性写入磁盘,这种方式可以减少磁盘操作次数,速度就会提高很多!

同时正因为它们实现了缓冲功能,所以要注意在使用BufferedOutputStream写完数据后,要调用flush()方法或close()方法,强行将缓冲区中的数据写出。否则可能无法写出数据。与之相似还BufferedReaderBufferedWriter两个类。

BufferedInputStreamBufferedOutputStream类就是实现了缓冲功能的输入流/输出流。使用带缓冲的输入输出流,效率更高,速度更快。

 四. OutPutStream

1. 常用的字节输出流

  • OutputStream
  • FileoutputStream
  • BufferedOutputStream (BufferedOutputStream 不是OutputStream的直接实现子类,是FilterOutputStream的子类)

它们的区别与用途:

(1)OutputStream: 字节输出流的基类。在这个类中常用的方法有wirte、close和flush(即刷新输出流,把数据马上写到输出流中)

(2)FileOutputStream:用于写文件的输出流

(3)BufferedOutputStream:同BufferedInputStream,可以提高效率。

2. FileOutputStream的用法

 1 package com.test.a;
 2 
 3 import java.io.FileOutputStream;
 4 import java.io.IOException;
 5 
 6 public class Test {
 7     public static void main(String args[]) throws IOException {
 8         FileOutputStream fileOutputStream=new FileOutputStream("C:\\Users\\hermioner\\Desktop\\test.txt",true);
 9         String string="为了中国梦,为了民族的伟大复兴,为了老百姓的幸福";
10         byte b[]=string.getBytes();
11         fileOutputStream.write(b);
12         fileOutputStream.close();
13     }
14 }
15 
16 
17 
18 //note:上面的true代表在原来路径下文本末尾追加字段,如果不写或者false则表示在文件的开头写,即完成了覆盖。如果上面给定的路径不存在,则会新创建。
View Code

3.BufferedOutputStream的用法

 1 public class Test {
 2     public static void main(String args[]) throws IOException {
 3         FileOutputStream fileOutputStream=new FileOutputStream("C:\\Users\\hermioer\\Desktop\\test.txt");
 4         BufferedOutputStream bufferedOutputStream=new BufferedOutputStream(fileOutputStream);
 5         String string="为了中国梦,为了民族的伟大复兴,为了老百姓的幸福";
 6         byte b[]=string.getBytes();
 7         bufferedOutputStream.write(b);
 8         bufferedOutputStream.close();//BufferedOoutputStream中实际上没有close,调用的是父类的close。并且close方法中还调用了flush方法
 9     }
10 }
View Code

参考文献:

https://www.cnblogs.com/dongguacai/p/5658388.html

https://www.cnblogs.com/progor/p/9357676.html

https://blog.csdn.net/zhaoyanjun6/article/details/54894451

猜你喜欢

转载自www.cnblogs.com/Hermioner/p/9771986.html