查看原文
其他

Java的IO流之字节流

Java面试 2020-10-17

伙伴们~

开始今天的学习咯

IO流


先来认识一下IO流:

IO流用来处理设备之间的数据传输,Java对数据的操作是通过流的方式,用于操作流的类都在IO包中。


1)流按流向分为两种:

输入流,输出流。


2)流按操作类型分为两种:


字节流 :

字节流可以操作任何数据,因为在计算机中任何数据都是以字节的形式存储的


字节流的抽象父类:

InputStream/OutputStream


字符流 : 

字符流只能操作纯字符数据,比较方便。


字符流的抽象父类:

Reader/Writer


3)IO程序书写规范

使用前,导入IO包中的类

使用时,进行IO异常处理

使用后,释放资源

字节流


今天我们先来认识一下字节流


1)FileInputStream

字节流的输入,使用read()方法一次读取一个字节

把文件 zzz.txt 中的字节读取到控制台上~因为a、b、c等英文字符在底层是用 ASC 码的数字表示的,所以我们在控制台上读取的结果是数字


注意:

read()方法的返回值是int

因为字节输入流可以操作任意类型的文件,比如图片音频等,这些文件底层都是以二进制形式的存储的。


如果每次读取都返回 byte,有可能在读到中间的时候遇到 111111111(byte类型的-1),read() 方法遇到 -1 就会停止不读,后面的数据也就读不到了,


所以在读取的时候用 int 类型接收,像11111111会在其前面补上24个0,凑足4个字节,那么 byte 类型的 -1就变成 int 类型的 255 了。这样可以保证整个数据读完,而结束标记的-1就是 int 类型。


2)FileOutputStream

字节输出流 write() 一次写出一个字节

把字节写入到文件 yyy.txt 中


注:

1)如果不存在 yyy.txt 这个文件,程序会自动创建一个 yyy.txt


2)因为在执行 FileOutputStream() 方法的时候,会先把文件里面的内容清空,然后再来把我们要写的东西写入~


如果我们想要不删出文件里面的内容而是追加内容该如何做呢?


在FileOutputStream的构造方法中,有一个构造方法,存在一个appen参数,表示追加的意思,我们在这边设置一个 true ,表示我们是追加内容就可以了~



那么代码应该这样写~

字节流的拷贝


现在输入输出我们都掌握了,就可以搞事情了,我们来做一个拷贝图片的练习吧~


1)逐个字节的拷贝方式

这样就可以把图片copy了一份了~


上面这种通过逐个字节拷贝文件的方式,对小一点的文件还好,当对大一点文件进行拷贝的时候速度就会慢下来——效率太低~(在实际的开发中我们不考虑)


2)利用available()拷贝方法


查看API有如下的介绍



大致意思就是,available()方法可以获取到我们将要 copy 的文件的所有字节个数~这样我们就可以一次性读取需要copy的文件的数据,然后在一次性的输出出来~



但是这种方式也有一个弊端,比如我们想拷贝一个大一点的文件(像蓝光电影这种有10+G大~),那么我们在拷贝之前就需要创建一个10+G大小的数组,要知道这些程序都是放在Java虚拟机中运行的,而Java虚拟机是虚拟在计算机的内存中(内存也不会全给Java虚拟机,一般Java的虚拟机也就100+M)就可能会导致内存溢出~,所以一般也是不推荐的~


3)定义小数组拷贝方式

这个方法综合了上面的两种方式~

所以推荐这种方式来拷贝文件


4)利用缓冲思想进行拷贝


字节流一次读写一个数组的速度明显比一次读写一个字节的速度快很多,这是加入了数组这样的缓冲区效果,java本身在设计的时候,也考虑到了这样的设计思想,所以提供了字节缓冲区流


带缓冲的拷贝


1)BufferedInputStream 内置了一个缓冲区(数组),BufferedInputStream 会一次性从文件中读取8*1024个,存在缓冲区中,程序在读取时,就不用找文件了,直接从缓冲区中获取,直到缓冲区中所有的数据都被读取过,BufferedInputStream才重新从文件中读取8*1024个。


2)BufferedOutputStream 也内置了一个缓冲区(数组),程序向流中写出字节时,不会直接写到文件,先写到缓冲区中,直到缓冲区写满,BufferedOutputStream 才会把缓冲区中的数据一次性写到文件里。


那么小数组的读写和带Buffered的读取哪个更快?

定义小数组如果是8*1024个字节大小和B uffered 比较的话,定义小数组会略胜一筹,因为读和写操作的是同一个数组,而Buffered操作的是两个数组。


在缓冲中存在一个 flush() 刷新方法,可以把缓冲区中的内容输出来~ 


flush() 和 close() 方法的区别

(偷个懒,就不写代码演示了)

flush()方法

用来刷新缓冲区的,刷新后可以再次写出 。

close()方法

用来关闭流释放资源的的,如果是带缓冲区的流对象调用了 close() 方法,不但会关闭流,还会再关闭流之前刷新缓冲区,关闭后不能再进行写出操作~

流的标准处理异常代码


Java1.6版本及其以前的处理方式

try finally嵌套

原则就是当程序出现问题时,尽量把流关闭,不要占用资源~



Java 1.7的版本以后的写法



原理

在 try() 中创建的流对象必须实现了 AutoCloseable 这个接口,实现了 AutoCloseable 接口以后 , 在 try 后面的大括号 {}中的读写代码执行后,就会自动调用流对象的 close 方法将流关掉~ 


今天就到这里了

再见了


扩展阅读

Java中操作文件的类——File类

Java中的异常

    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存