文件在程序中是以流的形式来传输的。所以用Java来传输文件就得使用到Java IO流。
1、流的概念和作用
流:代表任何有能力产出数据的数据源对象或者是有能力接受数据的接收端对象
流的本质:数据传输,根据数据传输特性将流抽象为各种类,方便更直观的进行数据操作。
作用:为数据源和目的地建立一个输送通道
2、Java IO所采用的模型
Java的IO模型设计非常优秀,它使用Decorator(装饰者)模式(这篇博文详细说明了什么是装饰者模式 传送门),按功能划分Stream,您可以动态装配这些Stream,以便获得您需要的功能。
例如,您需要一个具有缓冲的文件输入流,则应当组合使用FileInputStream和BufferedInputStream。
3、IO流的分类
①、根据数据流向不同分为:输入流和输出流。
输出:把程序(内存)中的内容输出到磁盘、光盘等存储设备中
输入:读取外部数据(磁盘、光盘等存储设备的数据)到程序(内存)中
②、根据处理数据类型的不同分为:字节流和字符流。
字节流:可以用于读写二进制文件及任何类型文件。
字符流:可以用于读写文本文件。
字节流和字符流的区别
字符流的由来: Java中字符是采用Unicode标准,一个字符是16位,即一个字符使用两个字节来表示。为此,JAVA中引入了处理字符的流。因为数据编码的不同,从而有了对字符进行高效操作的流对象。本质其实就是基于字节流读取时,去查了指定的码表。
两者的区别:(1字符 = 2字节 、 1字节(byte) = 8位(bit) 、 一个汉字占两个字节长度)
- 读写单位不同:字节流以字节为单位,字符流以字符为单位,根据码表映射字符,一次可能读多个字节。
- 处理对象不同:字节流能处理所有类型的数据(如图片、avi等),而字符流只能处理字符类型的数据。
- 缓存不同:字节流在操作的时候本身是不会用到缓冲区的,是文件本身的直接操作的;而字符流在操作的时候下后是会用到缓冲区的,是通过缓冲区来操作文件。
总结:优先选用字节流。因为硬盘上的所有文件都是以字节的形式进行传输或者保存的,包括图片等内容。字符只是在内存中才会形成的,所以在开发中,字节流使用广泛。除非处理纯文本数据(如TXT文件),才优先考虑使用字符流,除此之外都使用字节流。
③、根据功能的不同分为:节点流和处理流。
节点流:可以从或向一个特定的地方(节点)读写数据。如FileInputStream,FileReader。
处理流:是对一个已存在的流的连接和封装,通过所封装的流的功能调用实现数据读写。如BufferedReader。处理流的构造方法总是要带一个其他的流对象做参数。一个流对象经过其他流的多次包装,称为流的链接。
节点流是直接作用在文件上的流,可以理解为一个管道,文件在管道中传输。
处理流是作用在已有的节点流基础上,是包在节点流的外面的管道(可多层),其目的是让管道内的流可以更快的传输。
4、四个基本的抽象流类型,所有的流都继承这四个。
输入流
输出流
字节流
InputStream
OutputStream
字符流
Reader
Writer
下图是Java IO流的整体架构图,后面的博客会详细的讲解这些流使用:
当看到上面这张图的时候会感到很懵逼,因为这么多的类在使用时是选择字节流输入输出还是选择字符流输入输出呢?其实并不难。
- 如果你要将磁盘光盘中的数据读到程序中,那就选择输入流,反之则是输出流。
- 如果你要传输的是音频视频数据,那就肯定是字节流。如果单独是纯文本文件(如TXT),那就字符流。其实所有数据都可以使用字节流,只是效率高低问题。
- 如上面两个都确定了,就可以选出一个合适的节点流,然后再根据你的需求是否需要额外功能(比如是否需要转换流、高效流等)。
5、IO流常用到的五类一接口
Java IO流中所有的接口和类都放在java.io这个包下。其中最重要的就是5个类和一个接口。5个类指的是File、OutputStream、InputStream、Writer、Reader;一个接口指的是Serializable。如掌握了这些IO的核心使用方法,那么就能把Java IO流玩弄于股掌之中,将它放在手中任意盘它。
它们的详细介绍如下:
①. File(文件特征与管理):File类是对文件系统中文件以及文件夹进行封装的对象,可以通过对象的思想来操作文件和文件夹。 File类保存文件或目录的各种元数据信息,包括文件名、文件长度、最后修改时间、是否可读、获取当前文件的路径名,判断指定文件是否存在、获得当前目录中的文件列表,创建、删除文件和目录等方法。
②. InputStream(二进制格式操作):抽象类,基于字节的输入操作,是所有输入流的父类。定义了所有输入流都具有的共同特征。
③. OutputStream(二进制格式操作):抽象类。基于字节的输出操作。是所有输出流的父类。定义了所有输出流都具有的共同特征。
④. Reader(文件格式操作):抽象类,基于字符的输入操作。
⑤. Writer(文件格式操作):抽象类,基于字符的输出操作。
⑥. RandomAccessFile(随机文件操作):一个独立的类,直接继承至Object.它的功能丰富,可以从文件的任意位置进行存取(输入输出)操作。
⑦. Serializable(序列化操作):是一个空接口,为对象提供标准的序列化与反序列化操作。
6、Java IO流对象介绍
①、字节输入流InputStream
根据上图介绍各个类的作用:
- InputStream:字节输入流基类,是所有的字节输入流的父类,它是一个抽象类。
- FileInputSream:文件输入流。它通常用于对文件进行读取操作。
- FilterInputStream :过滤流。作用是为基础流提供一些额外的功能。装饰者模式中处于装饰者,具体的装饰者都要继承它,所以在该类的子类下都是用来装饰别的流的,也就是处理类。
- BufferedInputStream:缓冲流。对处理流进行装饰,增强,内部会有一个缓存区,用来存放字节,每次都是将缓存区存满然后发送,而不是一个字节或两个字节这样发送。效率更高。
- DataInputStream:数据输入流。它是用来装饰其它输入流,它“允许应用程序以与机器无关方式从底层输入流中读取基本 Java 数据类型”。
- PushbakInputStream:回退输入流。java中读取数据的方式是顺序读取,如果某个数据不需要读取,需要程序处理。PushBackInputStream就可以将某些不需要的数据回退到缓冲中。
- ObjectInputStream:对象输入流。用来提供对“基本数据或对象”的持久存储。通俗点讲,也就是能直接传输对象(反序列化中使用)。
- PipedInputStream:管道字节输入流。它和PipedOutputStream一起使用,能实现多线程间的管道通信。
- SequenceInputStream:合并输入流。依次将多个源合并成一个源。
- StringBufferInputStream:字符相关流。已经过时不多说。
- ByteArrayInputStream:字节数组输入流,该类的功能就是从字节数组(byte[])中进行以字节为单位的读取,也就是将资源文件都以字节的形式存入到该类中的字节数组中去,我们拿也是从这个字节数组中拿。
②、字节输出流OutputStream
根据上图介绍各个类的作用:
- OutputStream:字节输出流基类,是所有的字节输出流的父类,它是一个抽象类。
- FileOutputStream:文件输出流。该类实现了一个输出流,将数据输出到文件。
- FilterOutputStream :过滤流。用来封装其它的输出流,并为它们提供额外的功能(序列化中使用)。它主要包括BufferedOutputStream, DataOutputStream和PrintStream。
- BufferedOutputStream:缓冲输出流。给输出流提供缓冲功能。
- DataOutputStream:是用来装饰其它输出流,将DataOutputStream和DataInputStream输入流配合使用,“允许应用程序以与机器无关方式从底层输入流中读写基本 Java 数据类型”。
- PrintStream:是用来装饰其它输出流。它能为其他输出流添加了功能,使它们能够方便地打印各种数据值表示形式。
- ObjectOutputStream:对象输出流。该类将实现了序列化的对象序列化后写入指定地方。
- PipedOutputStream:管道字节输出流。它和PipedInputStream一起使用,能实现多线程间的管道通信,是管道的发送端。
- ByteArrayOutputStream:字节数组输出流。该类实现了一个输出流,其数据被写入由byte数组充当的缓冲区,缓冲区会随着数据的不断写入而自动增长。
③、字符输入流Reader
根据上图介绍各个类的作用:
- Reader:是所有的输入字符流的父类,它是一个抽象类。
- CharReader、StringReader 是两种基本的介质流,它们分别将Char 数组、String中读取数据。
- PipedReader 是从与其它线程共用的管道中读取数据。
- BufferedReader是一个装饰器,它和其子类LineNumberReader负责装饰其它Reader对象。
- InputStreamReader:是一个连接字节流和字符流的桥梁,它将字节流转变为字符流。FileReader 可以说是一个达到此功能、常用的工具类,在其源代码中明显使用了将FileInputStream 转变为Reader 的方法。我们可以从这个类中得到一定的技巧。Reader 中各个类的用途和使用方法基本和InputStream 中的类使用一致。后面会有Reader 与InputStream 的对应关系。
- FilterReader 是所有自定义具体装饰流的父类,其子类PushbackReader 对Reader对象进行装饰,会增加一个行号。
④、字符输出流Writer
根据上图介绍各个类的作用:
- Writer:是所有的输出字符流的父类,它是一个抽象类。
- CharArrayWriter、StringWriter 是两种基本的介质流,它们分别向Char 数组、String 中写入数据。PipedWriter 是向与其它线程共用的管道中写入数据,
- BufferedWriter 是一个装饰器为Writer 提供缓冲功能。
- PrintWriter 和PrintStream 极其类似,功能和使用也非常相似。
- OutputStreamWriter:是OutputStream 到Writer 转换的桥梁,它的子类FileWriter 其实就是一个实现此功能的具体类(具体可以研究一SourceCode)。功能和使用和OutputStream 极其类似。