Java IO通常包含两个部分:html
1.java.io包中堵塞型IO;java
2.java.nio包中的非堵塞型IO,一般称为New IO。数据库
java.io包下,分为四大块近80个类:数组
一、基于字节操做的I/O接口:InputStream和OutputStream缓存
二、基于字符操做的I/O接口:Writer和Reader网络
三、基于磁盘操做的I/O接口:File多线程
四、基于网络操做的I/O接口:Socket(不在java.io包下)dom
影响IO性能的无非就是两大因素:数据的格式及存储的方式,前两类主要是数据格式方面的,后两个类是存储方式方面的:本地和网络。函数
咱们不多单独使用哪一个类来实现IO操做,平时都是几个类合起来使用,这其实体现了一种装饰器模式源码分析
字节流能够处理任意类型的数据,而字符只能处理字符类型的数据
在Java中把不一样的输入/输出源抽象表述为"流"。流是一组有顺序的字节集合,是对数据传输的总称或抽象。
流有输入和输出,输入时是流从数据源流向程序。输出时是流从程序传向数据源,而数据源能够是内存,文件,网络或程序等。
Java采用unicode编码,通讲,2个字节来表示一个字符。
在0~127整数之间的字符映射,unicode向下兼容ASCII,也就是1个字节表示一个字符。
一个中文或英文字符的unicode编码都占2个字节。
编码方式 | 英文字符 | 中文字符 |
---|---|---|
GB 23十二、GBK | 1 | 2 |
UTF-8 | 1 | 3-4 |
UTF-16 | 2 | 3-4 |
UTF-32 | 4 | 4 |
咱们先来看看类图:
FileInputStream:从文件中读取数据。
ByteArrayInputStream:将内存中的Byte数组适配为一个InputStream。
StringBufferInputStream:将内存中的字符串适配为一个InputStream,内部实现用的是StringBuffer。
该类被Deprecated。主要缘由是StringBuffer不该该属于字节流,因此推荐使用StringReader。
SequenceInputStream:将多个流对象转化成一个InputStream。
PipedInputStream:用于从管道中读取数据,在流中实现了管道的概念。
ObjectInputStream: 该流容许读取或写入用户自定义的类(对象)。
FilterInputStream:装饰器类,为其它InputStream类提供功能。java对I/O访问多提供的同步机制是过滤流,保证某时刻只有一个线程访问一个I/O流。
DataInputStream:通常和DataOutputStream配对使用,完成基本数据类型的读写。
BufferedInputStream:使用该对象阻止每次读取一个字节都会频繁操做IO。将字节读取一个缓存区,从缓存区读取。
LineNumberInputStream:跟踪输入流中的行号。可调用getLineNumber和 setLineNumber(int)方法获得和设置行号。
PushbackInputStream: 能够在读取最后一个byte 后将其放回到缓存中。主要用在编译器的语法、词法分析部分。
ByteArrayOutputStream:在内存中建立一个buffer。全部写入此流中的数据都被放入到此buffer中。
FileOutputStream:将信息写入文件中。
PipedOutputStream:任何写入此对象的信息都被放入对应PipedInputStream 对象的缓存中,从而完成线程的通讯,实现了“管道”的概念。
FilterOutputStream:实现装饰器功能的抽象类。为其它OutputStream对象增长额外的功能。
DataOutputStream:使用它能够写入基本数据类型。
BufferedOutputStream:使用它能够避免频繁地向IO写入数据,数据通常都写入一个缓存区,在调用flush方法后会清空缓存、一次完成数据的写入。
PrintStream:产生具备格式的输出信息。
System.in, System.out, System.error(注:Java标准输入、输出、错误输出)是PrintStream的实例。
咱们在写入文件的时候,经常由于要保存的是一个对象,也就是一个obj,可是里面的变量又不少,咱们不可能挨个申明,一个个写入,这时候,咱们就可使用对象的序列化与反序列化。
序列化就是对象到保存文件的过程。
反序列化就是从保存的文件,转换为对象的过程。
通常在如下几种状况下,咱们可能会用到序列化:
a)当你想把的内存中的对象状态保存到一个文件中或者数据库中时候;
b)当你想用套接字在网络上传送对象的时候;
c)当你想经过RMI传输对象的时候。
管道主要用来实现同一个虚拟机进程中的两个线程进行交流。所以,一个管道既能够做为数据源媒介也可做为目标媒介。
须要注意的是java中的管道和Unix/Linux中的管道含义并不同,在Unix/Linux中管道能够做为两个位于不一样空间进程通讯的媒介,而在java中,管道只能为同一个JVM进程中的不一样线程进行通讯。
BufferedInputStream顾名思义,就是在对流进行写入时提供一个buffer来提升IO效率。
在进行磁盘或网络IO时,原始的InputStream对数据读取的过程都是一个字节一个字节操做的,而BufferedInputStream在其内部提供了一个buffer,在读数据时,会一次读取一大块数据到buffer中,这样比单字节的操做效率要高的多,特别是进程磁盘IO和对大量数据进行读写的时候。
使用BufferedInputStream十分简单,只要把普通的输入流和BufferedInputStream组合到一块儿便可。
(1)编码方式:而DataOutputStream则采用的是UTF-8。
(2)异常机制:DataOutputStream在经过write()向“输出流”中写入数据时,若产生IOException,会抛出。
(3)构造函数:DataOutputStream的构造函数只有一个:DataOutputStream(OutputStream out)。即它只支持以输出流out做为“DataOutputStream的输出流”。
(4)目的:DataOutputStream的做用是装饰其它的输出流,它和DataInputStream配合使用:容许应用程序以与机器无关的方式从底层输入流中读写java数据类型。
(1)编码方式:PrintStream是输出时采用的是用户指定的编码(建立PrintStream时指定的),若没有指定,则采用系统默认的字符编码。
(2)异常机制:与其余输出流不一样,PrintStream 永远不会抛出 IOException;它产生的IOException会被自身的函数所捕获并设置错误标记,
用户能够经过 checkError() 返回错误标记,从而查看PrintStream内部是否产生了IOException。
(3)构造函数:在PrintStream的构造函数中,能“指定字符集”和“是否支持自动flush()操做”。所谓自动flush,就是往PrintStream写入的数据会马上调用flush()函数
(4)目的:PrintStream为其它输出流提供打印各类数据值表示形式,使其它输出流能方便的经过print(), println()或printf()等输出各类格式的数据。
(01) out是System.java的静态变量。
(02) 并且out是PrintStream对象,PrintStream.java中有许多重载的println()方法。
FileOutputStream fdOut = new FileOutputStream(FileDescriptor.out);
setOut0(new PrintStream(new BufferedOutputStream(fdOut, 128), true));
将这两句话细分,能够划分为如下几步:
第1步 FileDescriptor fd = FileDescriptor.out;
第2步 FileOutputStream fdOut = new FileOutputStream(fd);
第3步 BufferedOutputStream bufOut = new BufferedOutputStream(fdOut, 128);
第4步 PrintStream ps = new PrintStream(bufout, true);
第5步 setOut0(ps);
(01) 获取FileDescriptor.java中的静态成员out,out是一个FileDescriptor对象,它其实是“标准输出(屏幕)”的标识符。
(02) 建立“标准输出(屏幕)”对应的“文件输出流”。
(03) 建立“文件输出流”对应的“缓冲输出流”。目的是为“文件输出流”添加“缓冲”功能。
(04) 建立“缓冲输出流”对应的“打印输出流”。目的是为“缓冲输出流”提供方便的打印接口,如print(), println(), printf();使其能方便快捷的进行打印输出。
(05) System.java中setOut0() 执行setOut0(ps),setOut0()是一个native本地方法,就是将ps设置为System.java的out静态变量。
Reader是全部的输入字符流的父类,它是一个抽象类。
CharReader、StringReader是两种基本的介质流,它们分别将Char数组、String中读取数据。
PipedReader是从与其它线程共用的管道中读取数据。
BufferedReader很明显就是一个装饰器,它和其子类负责装饰其它Reader对象。
FilterReader是全部自定义具体装饰流的父类。
Writer和Reader操做的目的就是操做字符,不是字节,设计Writer和Reader的目的是国际化,使IO操做支持16位的Unicode。
对于IO操做,不论是磁盘仍是网络,最终都是对字节的操做,而咱们平时写的程序都是字符形式的,因此在传输的过程当中须要进行转换。
在字符到字节的转换过程当中,咱们须要用到一个类:InputStreamReader。
InputStreamReader是一个链接字节流和字符流的桥梁,它将字节流转变为字符流。
注意:inputStream和reader,outputStream与write的函数都很类似,而且每次进行了IO操做,要记得close,
由于IO资源并不属于内存资源,并不会被GC回收,因此须要显示的手动的回收资源。
对于输出操做,close还会自动flush。
文件和文件夹的操做均可以用File来完成。
优势: RandomAccessFile 能够实现对文件的随机读写,可是他并非继承于以上4中基本虚拟类。
缺点:RandomAccessFile的方法有一个最大的局限,就是只能读写文件,不能读写其余IO节点。
使用场景:RandomAccessFile的一个重要使用场景就是网络请求中的多线程下载及断点续传。
mode中,有4中启动的方式:
"r" 以只读方式打开。调用结果对象的任何 write 方法都将致使抛出 IOException。
"rw" 打开以便读取和写入。若是该文件尚不存在,则尝试建立该文件。
"rws" 打开以便读取和写入,对于 "rw",还要求对文件的内容或元数据的每一个更新都同步写入到底层存储设备。
"rwd" 打开以便读取和写入,对于 "rw",还要求对文件内容的每一个更新都同步写入到底层存储设备。
注意:RandomAccessFile虽然能够设置了偏移的方法,但他不能实现中间插入的效果,若是你须要实现文本中间插入的话,要先将后面的文件内容拷贝,而后写入,最后在写入的写一行,将拷贝的东西复制回来。
FileDescriptor 是“文件描述符”。
FileDescriptor 能够被用来表示开放文件、开放套接字等。
以FileDescriptor表示文件来讲:当FileDescriptor表示某文件时,咱们能够通俗的将FileDescriptor当作是该文件。可是,咱们不能直接经过FileDescriptor对该文件进行操做;若须要经过FileDescriptor对该文件进行操做,则须要新建立FileDescriptor对应的FileOutputStream,再对文件进行操做。
FileDescriptor的对象in, out, err介绍
(01) in -- 标准输入(键盘)的描述符
(02) out -- 标准输出(屏幕)的描述符
(03) err -- 标准错误输出(屏幕)的描述符
java io系列01之 "目录"(很好值得推荐)