java io流(核心:读进来,写出去)

一、流概念和作用

流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象。即数据在两设备间的传输称为流。流的本质是数据传输,根据数据传输特性将流抽象为各种类,方便更直观的进行数据操作。

二、流存在的意义

我们在进行数据传输时有这三个特点:1.数据的传输量很大;2.内存有限;3.带宽有限。所以需要使用流来解决这些问题。而流可以逐步的传输所有数据,不会占用太多的内存。例如下载文件时,并不会占用太多的内存,而是在内存中开辟一个缓冲区,一点一点的传输数据,当这个缓冲区满了后就直接写到磁盘。

三、流的原理浅析

java IO流共涉及40多个类,这些类看上去很杂乱,但实际上很有规则,而且彼此之间存在非常紧密的联系,Java IO流的40多个类都是从如下4个抽象类基类中派生出来的。
InputStream/Reader: 所有的输入流的基类,前者是字节输入流,后者是字符输入流。
OutputStream/Writer: 所有输出流的基类,前者是字节输出流,后者是字符输出流。
注:它们都是一些抽象基类,无法直接创建实例。

四、IO流的分类

java输入/输出流体系中常用的流的分类如下

InputStreamReader和OutputStreamWriter是字符和字节的桥梁,也可称之为字符转换流。原理:字节流+编码。
FileReader和FileWriter作为子类,仅作为操作字符文件的便捷类存在。当操作的字符文件,使用的是默认编码表时可以不用父类,而直接使用子类完成操作,简化代码。
一旦要指定其他编码时,不能使用子类,必须使用字符转换流。
public class InputStreamReader extends Reader
InputStreamReader 是字节流通向字符流的桥梁
public class OutputStreamWriter extends Writer
OutputStreamWriter 是字符流通向字节流的桥梁

五、按照流操作对象分类

1.按照流的流向分,可以分为输入流和输出流;

  • 输入流: 只能从中读取数据,而不能向其写入数据。
  • 输出流:只能向其写入数据,而不能向其读取数据。

2.按照操作单元划分,可以划分为字节流和字符流;
字节流和字符流的用法几乎完全一样,区别在于字节流和字符流所操作的数据单元不同,字节流操作的单元是数据单元为8位的字节,字符流操作的是数据单元为16位的字符。
设备上的数据无论是图片或者视频,文字,它们都以二进制存储的。二进制的最终都是以一个8位为数据单元进行体现,所以计算机中的最小数据单元就是字节。意味着,字节流可以处理设备上的所有数据,而字符流只能处理字符数据。 字符流能实现的功能字节流都能实现,反之不一定。

结论:只要是处理纯文本数据,就优先考虑使用字符流。 除此之外都使用字节流。

3.按照流的角色划分为节点流和处理流。
可以向一个特定的IO设备(如磁盘,网络)读/写数据的流,称为节点流。节点流也被称为低级流。当使用节点流进行输入/输出时程序直接连接到实际的数据源,和实际的输出/输入节点连接。
处理流则用于对一个已存在的流进行连接和封装,通过封装后的流来实现数据的读/写功能。处理流也被称为高级流。处理流也就是对流进行了再包装,从而达到优化系统性能的目的。


缓冲流:
缓冲流(buffering)是处理流的一种,它是要“套接”在相应的节点流之上,对读写的数据提供了缓冲的功能, 提高了读写的效率,同时增加了一些新的方法。例如:BufferedReader中的readLine方法, BufferedWriter中的newLine方法,对I/O进行缓冲是一种常见的性能优化,缓冲流为I/O流增加了内存缓冲区,增加缓冲区的两个目的:
(1)允许Java的I/O一次不只操作一个字符,这样可提高整个系统的性能;
(2)由于有缓冲区,使得在流上执行skip、mark和reset方法都成为可能。
缓冲区的工作原理:1、使用底层流对象从具体设备上获取数据,并将数据存储到缓冲区的数组内。2、通过缓冲区的read()方法从缓冲区获取具体的数据,这样就提高了效率。

//字符输入缓冲流
BufferedReader(Reader in)//创建一个32字节的缓冲区
BufferedReader(Reader in, int size)//size为自定义缓存区的大小

//字符输出缓冲流
BufferedWriter(Writer out)
BufferedWriter(Writer out, int size)
 
//字节输入缓冲流
BufferedInputStream(InputStream in)
BufferedInputStream(InputStream in, int size)
 
//字节输出缓冲流
BufferedOutputStream(OutputStream in)
BufferedOutputStream(OutputStream in, int size)
    
备注:
  (1)字节缓冲输入流BufferedInputStream除了支持read和skip方法以外,还支持其父类的mark和reset方法; 
  (2)BufferedReader提供了一种新的ReadLine方法用于读取一行字符串(以
或
分隔); 
  (3)BufferedWriter提供了一种新的newLine方法用于写入一个行分隔符; 
  (4)对于输出的缓冲流,BufferedWriter和BufferedOutputStream,写出的数据会先在内存中缓存,使用flush()方法将会使内存的数据立刻全部写出。

六、流的重要特性

1、流是Java 的1个类,但类不是流。
2、数据并不会在流里自动流动,因此需要我们调用流的方法,一次传输一定量的数据。
3、一个流对象只有一个传输方向,也就是说流是单向的, 数据要么从程序到设备(OutputStream), 要么从设备到程序(InputStream)。

七、何为NIO,和传统Io有何区别

我们使用InputStream从输入流中读取数据时,如果没有读取到有效的数据,程序将在此处阻塞该线程的执行。传统的输入流和输出流都是阻塞式的进行输入和输出。 传统的输入流、输出流都是通过字节的移动来处理的(即使我们不直接处理字节流,但底层实现还是依赖于字节处理)。也就是说,面向流的输入和输出一次只能处理一个字节,因此面向流的输入和输出效率通常不高。
    从JDk1.4开始,java提供了一系列改进的输入和输出处理的新功能,这些功能被统称为新IO(NIO)。新增了许多用于处理输入和输出的类,这些类都被放在java.nio包及其子包下,并且对原io的很多类都以NIO为基础进行了改写,新增了满足NIO的功能,所以从效率上来说IO和NIO差不了太多。
   NIO采用了内存映射对象的方式来处理输入和输出,NIO将文件或者文件的一块区域映射到内存中,这样就可以像访问内存一样来访问文件。通过这种方式来进行输入/输出比传统的输入和输出要快的多。

八、在开发中正确使用IO进行开发

如果是操作二进制文件那我们就使用字节流,如果操作的是文本文件那我们就使用字符流。尽可能多的使用处理流,这会使我们的代码更加灵活,复用性更好。

九、参考博文

(1)https://www.cnblogs.com/hopeyes/p/9736642.html
(2)https://www.jianshu.com/p/b6a2b5167f49
(3)https://blog.csdn.net/weixin_42194284/article/details/92832471
(4)https://www.cnblogs.com/zhaoyanjun/p/6292384.html
(5)https://www.cnblogs.com/zhaoyanjun/p/6292399.html(File类详情(有IO系列文章))
(6)https://blog.csdn.net/nightcurtis/article/details/51324105(流的使用等

原文地址:https://www.cnblogs.com/jasonboren/p/12196480.html