IO操作
一、File
<font style="background-color:rgb(248, 249, 250);">java.io</font>提供了<font style="background-color:rgb(248, 249, 250);">File</font>对象来操作文件和目录。构造<font style="background-color:rgb(248, 249, 250);">File</font>对象时,可以传入绝对路径,也可以传入相对路径。
windows用<font style="background-color:rgb(248, 249, 250);">\</font>作为路径分隔符,java需要用<font style="background-color:rgb(248, 249, 250);">\\</font>表示一个<font style="background-color:rgb(248, 249, 250);">\</font>。linux使用<font style="background-color:rgb(248, 249, 250);">/</font>作为路径分隔符。用<font style="background-color:rgb(248, 249, 250);">.</font>表示当前目录,<font style="background-color:rgb(248, 249, 250);">..</font>表示上级目录。
<font style="background-color:rgb(248, 249, 250);">File</font>对象有一个静态变量用来表示当前平台的系统分隔符:<font style="background-color:rgb(248, 249, 250);">separator</font>
<font style="background-color:rgb(248, 249, 250);">File</font>对象有3种形式表示路径:
<font style="background-color:rgb(248, 249, 250);">getPath()</font>:返回构造方法传入的路径<font style="background-color:rgb(248, 249, 250);">getAbsolutePath()</font>:返回绝对路径<font style="background-color:rgb(248, 249, 250);">getCanonicalPath()</font>:返回规范路径
1 | package org.example; |
<font style="background-color:rgb(248, 249, 250);">File</font>对象可以表示文件,也可以表示目录。
<font style="background-color:rgb(248, 249, 250);">isFile()</font>:是否是一个存在的文件<font style="background-color:rgb(248, 249, 250);">isDirectory()</font>:是否是一个存在的目录<font style="background-color:rgb(248, 249, 250);">canRead()</font>:是否可读<font style="background-color:rgb(248, 249, 250);">canWrite()</font>:是否可写<font style="background-color:rgb(248, 249, 250);">canExecute()</font>:是否可执行,对于目录而言,表示能否列出包含的文件和子目录<font style="background-color:rgb(248, 249, 250);">length()</font>:文件字节大小
1 | package org.example; |
<font style="background-color:rgb(248, 249, 250);">craeteNewFile()</font>:创建文件<font style="background-color:rgb(248, 249, 250);">delete()</font>:删除文件,删除目录时只有目录为空才能删除成功<font style="background-color:rgb(248, 249, 250);">createTempFile()</font>:创建临时文件<font style="background-color:rgb(248, 249, 250);">deleteOnExit()</font>:在JVM退出时自动删除该文件<font style="background-color:rgb(248, 249, 250);">mkdir()</font>:创建目录<font style="background-color:rgb(248, 249, 250);">mkdirs()</font>:创建目录并且创建不存在的父目录<font style="background-color:rgb(248, 249, 250);">list()</font>:列出文件名<font style="background-color:rgb(248, 249, 250);">listFiles()</font>:列出文件对象,好分辨哪个是目录,哪个是文件
1 | package org.example; |
Path类
二、OutputStream
<font style="background-color:rgb(248, 249, 250);">write</font>方法会写入一个字节到输出流,虽然传入的是<font style="background-color:rgb(248, 249, 250);">int</font>参数,但只会写入一个字节。
<font style="background-color:rgb(248, 249, 250);">flush()</font>方法将缓冲区的内容输出到目的地。因为向磁盘、网络写入数据的时候,出于效率的考虑,操作系统并不是输出一个字节就立刻写入到文件或者发送到网络,而是把输出的字节先放到内存的一个缓冲区里(本质上就是一个<font style="background-color:rgb(248, 249, 250);">byte[]</font>数组),等到缓冲区写满了,再一次性写入文件或者网络。
1 | package org.example; |
可以通过重载<font style="background-color:rgb(248, 249, 250);">void wirte(byte[])</font>来一次性写入多个字节。
1 | package org.example; |
上述代码如果发生异常就无法正确关闭资源,所以需要用<font style="background-color:rgb(248, 249, 250);">try(resource)</font>来保证无论是否发生IO错误都能正确关闭。
1 | package org.example; |
ByteArrayOutputStream
<font style="background-color:rgb(248, 249, 250);">ByteArrayOutputStream</font>实际上是把一个<font style="background-color:rgb(248, 249, 250);">byte[]</font>数组在内存中变成一个 <font style="background-color:rgb(248, 249, 250);">OutputStream</font>。
1 | package org.example; |
1 | package org.example; |
三、InputStream
<font style="background-color:rgb(248, 249, 250);">InpuStream</font>是一个抽象类,是所有输入流的超类。<font style="background-color:rgb(248, 249, 250);">read</font>是该类中最重要的方法。这个方法会读取输入流的下一个字节,并返回字节表示的int值,如果读到末尾会返回-1表示不能继续读取。
<font style="background-color:rgb(248, 249, 250);">FileInputStream</font>是<font style="background-color:rgb(248, 249, 250);">InpuStream</font>的一个子类。
<font style="background-color:rgb(248, 249, 250);">InpuStream</font>提供了两个重载方法来支持读取多个字节:
<font style="background-color:rgb(248, 249, 250);">int read(byte[] b)</font>:读取若干个字节并填充到<font style="background-color:rgb(248, 249, 250);">byte[]</font>数组,返回读取的字节数<font style="background-color:rgb(248, 249, 250);">int read(byte[] b,int off,int len)</font>:指定<font style="background-color:rgb(248, 249, 250);">byte[]</font>数组的偏移量和最大填充数
InputStream也有缓冲区。读取一个字节时,操作系统往往会一次性读取若干字节到缓冲区,并维护一个指针指向未读的缓冲区。每次我们调用<font style="background-color:rgb(248, 249, 250);">read()</font>读取下一个字节时,可以直接返回缓冲区的下一个字节,避免每次读一个字节都导致IO操作。当缓冲区全部读完后继续调用<font style="background-color:rgb(248, 249, 250);">read()</font>,则会触发操作系统的下一次读取并再次填满缓冲区。
1 | package org.example; |
ByteArrayInputStream
1 | package org.example; |
练习
1 | package org.example; |
四、Filter模式
JDK将<font style="background-color:rgb(248, 249, 250);">InputStream</font>和<font style="background-color:rgb(248, 249, 250);">OutputStream</font>分为两大类,避免过多的子类继承导致子类爆炸:
- 直接提供数据的基础类,如:
<font style="background-color:rgb(248, 249, 250);">FileInputStream</font>、<font style="background-color:rgb(248, 249, 250);">ByteArrayInputStream</font>、<font style="background-color:rgb(248, 249, 250);">ServletInputStream</font>等 - 提供额外附加功能的类,如:
<font style="background-color:rgb(248, 249, 250);">BufferedInputStream</font>、<font style="background-color:rgb(248, 249, 250);">CipherInputStream</font>等
1 | InputStream file = new FileInputStream("test.gz"); |
不管包装多少次,得到的对象始终是<font style="background-color:rgb(248, 249, 250);">InputStream</font>就可以正常读取。这种通过一个“基础”组件再叠加各种“附加”功能组件的模式,称之为Filter模式或者装饰器模式。
1 | package org.example; |
序列化
序列化必须实现<font style="background-color:rgb(248, 249, 250);">java.io.Serializable</font>接口。序列化本质就是将一个java对象转化为<font style="background-color:rgb(248, 249, 250);">byte[]</font>数组。
1 | package org.example; |
五、Reader
是java的IO库中提供的另一个输入流接口。与<font style="background-color:rgb(248, 249, 250);">InputStream</font>的区别在于:
<font style="background-color:rgb(248, 249, 250);">IntputStream</font>是一个字节流,以<font style="background-color:rgb(248, 249, 250);">byte</font>为单位读取;<font style="background-color:rgb(248, 249, 250);">Reader</font>是一个字符流,以<font style="background-color:rgb(248, 249, 250);">char</font>为单位读取。
<font style="background-color:rgb(248, 249, 250);">FileReader</font>是<font style="background-color:rgb(248, 249, 250);">Reader</font>的一个子类,可以打开文件并获取<font style="background-color:rgb(248, 249, 250);">Reader</font>
1 | package org.example; |
CharArrayReader
与<font style="background-color:rgb(248, 249, 250);">ByteArrayInputStream</font>类似。
1 | package org.example; |
<font style="background-color:rgb(248, 249, 250);">StringReader</font>可以直接把<font style="background-color:rgb(248, 249, 250);">String</font>作为数据源。
InputStreamReader
除了<font style="background-color:rgb(248, 249, 250);">CharArrayReader</font>与<font style="background-color:rgb(248, 249, 250);">StringReader</font>,普通的<font style="background-color:rgb(248, 249, 250);">Reader</font>都是基于<font style="background-color:rgb(248, 249, 250);">InputStream</font>构造的,都需要从<font style="background-color:rgb(248, 249, 250);">InputStream</font>中读入<font style="background-color:rgb(248, 249, 250);">byte</font>,再根据编码设置转换为<font style="background-color:rgb(248, 249, 250);">char</font>。
<font style="background-color:rgb(248, 249, 250);">InputStreamReader</font>可以把任何<font style="background-color:rgb(248, 249, 250);">InputStream</font>转换为<font style="background-color:rgb(248, 249, 250);">Reader</font>。
1 | package org.example; |
六、PrintStream和PrintWriter
<font style="background-color:rgb(248, 249, 250);">PrintStream</font>是一种<font style="background-color:rgb(248, 249, 250);">FilterOutputStream</font>,在<font style="background-color:rgb(248, 249, 250);">OutputStream</font>的接口上额外提供了一些写入各种数据类型的方法。
<font style="background-color:rgb(248, 249, 250);">System.out</font>是系统默认提供的<font style="background-color:rgb(248, 249, 250);">PrintStream</font>,<font style="background-color:rgb(248, 249, 250);">System.err</font>是系统默认提供的标准错误输出。
<font style="background-color:rgb(248, 249, 250);">PrintStream</font>和<font style="background-color:rgb(248, 249, 250);">OutputStream</font>相比,除了添加了一组<font style="background-color:rgb(248, 249, 250);">print() / println()</font>方法,可以打印各种数据类型,比较方便外,它还有一个额外的优点,就是不会抛出<font style="background-color:rgb(248, 249, 250);">IOException</font>,这样我们在编写代码的时候,就不必捕获<font style="background-color:rgb(248, 249, 250);">IOException</font>。
1 | package org.example; |
<font style="background-color:rgb(248, 249, 250);">PrintStream</font>最终输出的总是<font style="background-color:rgb(248, 249, 250);">byte</font>数据,而<font style="background-color:rgb(248, 249, 250);">PrintWriter</font>则是扩展了<font style="background-color:rgb(248, 249, 250);">Writer</font>接口,它的<font style="background-color:rgb(248, 249, 250);">print() / println()</font>方法最终输出的是<font style="background-color:rgb(248, 249, 250);">char</font>数据。两者的使用方法几乎是一模一样的。
1 | package org.example; |
七、Files
1 | package org.example; |
