java基础io流——OutputStream和InputStream的故事(温故知新)

591 阅读4分钟

参考:https://blog.csdn.net/weixin_36586120/article/details/80486112

io流概述:

IO流用来处理设备之间的数据传输,上传文件和下载文件,Java对数据的操作是通过流的方式,Java用于操作流的对象都在IO包中。

IO流分类

按照数据流向

输入流 读入数据

输出流 写出数据

按照数据类型

字节流

字符流

什么情况下使用哪种流呢?

如果数据所在的文件通过windows自带的记事本打开并能读懂里面的内容,就用字符流,其他用字节流。

如果你什么都不知道,就用字节流。

IO流常用基类

字节流的抽象基类:

InputStream ,OutputStream。

字符流的抽象基类:

Reader , Writer。

注:
由这四个类派生出来的子类名称都是以其父类名作为子类名的后缀。
如:InputStream的子类FileInputStream。
如:Reader的子类FileReader。

OutputStream的子类FileOutputStream

构造方法:

FileOutputStream(File file)

FileOutputStream(String name)

推荐第二种构造方法:

1.  FileOutputStream outputStream = new FileOutputStream("a.txt");

创建字节输出流对象了做了几件事情:

A:调用系统功能去创建文件

B:创建outputStream对象 

C:把foutputStream对象指向这个文件

通过字节输出流写出数据到文本

public void write(int b)

 public void write(byte[] b) 

public void write(byte[] b,int off,int len)

从方法中可看出,只能通过字节写出

outputStream.write("hello".getBytes()); 文本中出现hello

 outputStream.write(96) //文本中出现 a 

 byte[] bys={97,98,99,100,101}; 

outputStream.write(bys,1,3); 文本中出现bcd 

如此写出,文本中数据不会换行,不会追加,每次写出都是覆盖原来。

追加:
FileOutputStream outputStream = new FileOutputStream("a.txt",true); //第二个参数true设置为可追加。
换行 \n\r :

for (int i = 0; i <5 ; i++) { 

 outputStream.write("hello".getBytes()); 

 outputStream.write("\n\r".getBytes()); 

 }

注:用完流一定要记得关闭。

outputStream.close();

完整示例:

InputStream的子类FileInputStream

FileInputStream的构造方法

FileInputStream(File file)
FileInputStream(String name)

推荐第二种构造方法:

 FileInputStream inputStream = new FileInputStream("a.txt");

把刚才写的数据现在读取到控制台:

public int read()
public int read(byte[] b)

第一个read是读一个字节,第二个read是读一个字节数组。

//读一个字节
int by = 0;
while ((by=inputStream.read())!=-1){
      System.out.println((char)by);
}

读到没数据了就返回-1,这个用来判断是否读完。 

//读一个字节数组,一般是1024大小 

int len = 0 ;

 byte[] bys = new byte[1024]; 

while ((len = inputStream.read(bys)) != -1) { 

 System.out.println(new String(bys,0,len));

 } 

两个read的返回值略有不同,read()返回读取的字节,读到末尾返回-1,read(byte[] b)返回的是读到的字节个数,读到的字节放在了bytes字节数组里,读到末尾没数据了返回-1。

同样的用完了流,也要及时的关闭,以防占用内存。

inputStream.close();

完整示例: 

 建议以字节数组的方式读取数据。

字节流复制文件

利用输入流读取一个文件里的字节,再利用输出流将读取到的字节写出到另一个文件中(不存在会自动创建)

注:复制文本、图片、mp3、视频等的方式一样。

字节流一次读写一个数组的速度明显比一次读写一个字节的速度快很多,这是加入了数组这样的缓冲区效果。

java本身在设计的时候,也考虑到了这样的设计思想(装饰设计模式后面讲解),所以提供了字节缓冲区流。

字节缓冲输出流
BufferedOutputStream
字节缓冲输入流
BufferedInputStream

BufferedOutputStream

BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("a.txt",true)); bos.write("hello world".getBytes());

 bos.close();

BufferedInputStream

BufferedInputStream bis = new BufferedInputStream(new FileInputStream("a.txt"));

 byte[] bytes = new byte[1024];

 int len = 0; 

while ((len=bis.read(bytes)) != -1) { 

 System.out.println(new String(bytes,0,len));

 } 

bis.close(); 

注: - 成员方法与字节流基本一样,字节缓冲流的作用就是提高输入输出的效率。 - 构造方法可以指定缓冲区的大小,但是我们一般用不上,因为默认缓冲区大小就足够了。 - 为什么不传递一个具体的文件或者文件路径,而是传递一个OutputStream对象呢?原因很简单,字节缓冲区流仅仅提供缓冲区,为高效而设计的。但是呢,真正的读写操作还得靠基本的流对象实现。

复制文件的升级: 

BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("E:\\modern-java.pdf")); 

BufferedInputStream bis = new BufferedInputStream(new FileInputStream("F:\\汤包\\慕课大巴\\modern-java.pdf")); 

int len = 0; byte[] bytes =new byte[1024]; 

while ((len=bis.read(bytes)) != -1) { 

 bos.write(bytes,0,len);

 } 

bis.close(); 

bos.close();

测试:四种复制文件的效率高低