IO
[TOC]
File类
简介
java.io.File类是专门对文件进行操作的类,但只是对文件本身进行操作,无法对文件内容进行操作。File类中,包含了与文件的有关信息,如长度,修改时间,绝对路径,读写属性等等,是对一个文件的抽象表示。其中定义了许多与平台无关的方法,比如创建、删除、重命名等等。File类实现了Serializable接口和Comparable
这里说的文件,同时也包含了目录。
字段
- public static final char separatorChar //与系统有关的默认名称分割符,类Unix系统中,此字段的值为’/‘,在Windows系统中,此字段的值为’\‘
- public static final String separator //同上,只不过是String格式
- public static final char pathSeparatorChar //与系统有关的路径分割符,类Unix系统中,此字段的值为’:’,在Windows系统中,此字段的值为’;’
- public static final String pathSeparator //同上,只不过是String格式
构造方法
- public File(String pathname)通过pathname为路径创建File对象。如果pathname是相对路径的话,则是相对java的系统属性user.dir中的路径。
- public File(File parent, String child)根据 parent 抽象路径名和 child 路径名字符串创建一个新 File对象。
- public FIle(String parent, String child)根据parent抽象路径名和 child 路径名字符串创建一个新 File对象。
- public File(URI uri)通过给钉的file:转换成一个抽象的路径名来创建一个新的File对象。
常用方法
- public boolean canRead() //是否可读
- public boolean canWrite() //是否可写
- public boolean exists() //文件是否存在
- public boolean isDirectory() //是不是目录/路径
- public boolean isFile() //是否是文件
- public boolean isHidden() //是否是隐藏的
- public long lastModified() //最后修改时间
- public long length() //以字节为单位(文件长度)
- public String getName() //获取文件名称
- public String getPath() //创建File对象时,使用什么路径就返回什么路径:是相对就返回相对,是绝对就返回绝对
- public String getAbsolutePath() //返回此File对象的绝对路径名
- public File getAbsoluteFile()//返回此抽象路径名的绝对路径名形式。等同于
new File(this.getAbsolutePath())
。 - public String getParent() //获取父目录,根据创建的时候提供的路径去返回,如果创建的时候没有父目录,则返回’.’,代表当前的目录
- public boolean createNewFile() //不存在时创建此文件对象所代表的空文件
- public boolean delete() //删除文件。如果是目录必须是空才能删除
- public boolean mkdir() //创建此抽象路径名指定的目录
- public boolean mkdirs() //创建此抽象路径名指定的目录,包括所有必需但不存在的父目录
- public boolean renameTo(File dest) //重新命名此抽象路径名表示的文件浏览目录中的文件和子目录
- public String[] list() //返回此目录中的文件名和目录名的数组
- public File[] listFiles() //返回此目录中的文件和目录的File实例数组
- public File[] listFiles(FilenameFilter filter) //返回此目录中满足指定过滤器的文件和目录
java.io.FilenameFilter接口:实现此接口的类实例可用于过滤文件名
一个简单的使用例子
1 | import java.io.File; |
RandomAccessFile类
简介
RandomAccessFile类的功能较之其他io包中的输出流输入流都要丰富得多,既可以往文件里面读数据,也可以往文件里面写数据;同时,它还有一个很大的特点,可以使用seek方法来进行定位,也就是说我们可以访问文件的任意位置。
构造方法
- RandomAccessFile(File file, String mode) //创建从中读取和向其中写入(可选)的随机访问文件流,该文件由file参数指定
- RandomAccessFile(String name, String mode) //创建从中读取和向其中写入(可选)的随机访问文件流,该文件由name参数指定
方法
- void close() //关闭并释放与之相关联的资源
- FileChannel getChannel() //返回此文件关联的FileChannel对象
- FileDescriptor getFD() //返回此文件的FileDescriptor对象
- long getFilePointer() //获得当前文件指针的位置
- long length() //获得文件大小
- int read()
- int read(byte[] b)
- int read(byte[] b, int off, int len)
- Xxx readXxx()
//一些比较常用的读取方法
- String readLine() //读取一个文本行
- String readUTF() //读取一个两个字节的数据,然后字节内容解释为UTF-8修改版的字符,转换并返回
- int skipBytes(int n) //跳过n个字节内容
- void write(int b)
- void write(byte[] b)
- void write(byte[] b, int off, int len)
- void writeXxx(Xxx v)
//一系列常用的写入方法
- void writeBytes(String s) //写入一个字符串
- void writeUTF(String str) //使用modified UTF-8编码以与机器无关的方式将一个字符串写入该文件
- void seek(long pos) //将文件指针移动到指定位置
- void setLength(long newLength) //设置当前文件的长度
例子
将指定文件的第一行替换为Hello,并输出原内容,最后一行替换为Goodbye,并输出原内容。
1 | import java.io.*; |
FileDescriptor类
简介
文件描述符类的实例用作与基础机器有关的某种结构的不透明句柄,该结构表示开放文件、开放套接字或者字节的另一个源或接收者。文件描述符的主要实际用途是创建一个包含该结构的 FileInputStream
或 FileOutputStream
。 一般来说,应用程序不应创建自己的文件描述符。
字段
- public static FileDescriptor err //标准错误流的句柄
- public static FileDescriptor in //标准输出流的句柄
- public static FileDescriptor out //标准输出流的句柄
构造方法
- public FileDecriptor() //构造一个无效的FileDescriptor对象
方法
- public boolean valid() //测试此文件爱女描述符是否有效
- public void sync() //强制所有系统缓冲区与基础设备同步。
三言两语
主要的获取方式是通过调用FileInputStream类或者FileOutputStream类中的getFD()方法来获得对应的实例。
至于使用方式。。。不详
IO类
IO相关类树和结构图
1 | graph LR |
字节流和字符流
字符流是在字节流的基础上演变而来的,相对于字节流,字符流可以更加高效、更加方便的读取数据。字符流相对于字节流的本质区别就是在读取的时候,会查询指定的码表,然后读取一个字符。在java中,字节是8位,占一个字节,有符号;字符的话,是一个16位,占两个字节的Unciode码,无符号。
在处理不同的数据对象时,会根据实际情况而采取不同的流对象。比如在处理文本方面的数据时,一般都采用字符流;而在处理其他方面的数据,比如视频,音频,图像等时,会考虑采取字节流。
字符流中Reader和Writer的主要方法
Reader
abstract void close() //关闭该流并释放与之关联的所有资源
void mark(int radAheadLimit) //标记流中的当前位置
boolean markSupported() //判断此流是否支持mark()操作
int read() //读取单个字节
此方法返回读取到的字符值(0~65535),如果已到达末尾,返回-1。
int read(char[] buf) //将字符读入数组
abstract int read(char[] buf, int off, int len) //将字符读入数组的某一部分
以上两个read方法都返回成功读取的字符数,如果已到达末尾,返回-1。两者都是阻塞的,也就是说在输入可用、发生I/O错误或者已达到流的末尾前,都是阻塞的。read()也是。
boolean ready() //判断是否准备读取此流
void reset() //将此输入流重新定位到最后一次对此输入流掉哦你个mark方法时的位置
long skip(long n) //跳过字符
Writer
- Writer append(char c) //将指定字符添加到此Writer
- Writer append(CharSequence csq) //将指定的字符序列添加到此Writer
- Writer append(CharSequence csq, int start, int end) //将指定的字符序列添加到此Writer
- abstract void flush() //刷新该流中的缓冲区
- abstract void close() //关闭该流,但是关闭前会刷新该流的缓冲区
- void write(int c) //写入单字符
- void write(char[] cbuf) //写入字符数组
- abstract void wirte(char[] cbuf, int off, int len) //写入字符数组的某一部分
- void write(String str) //写入字符串
- void write(String str, int off, int len) //写入字符串的某一部分
write和append两者实际上并没有多大的区别,只不过append是从Appendable继承过来的,其规约的是返回值是对象本身。
例子
下面是一个对Reader和Writer中一些方法应用的例子
1 | import java.io.*; |
字节流中InputStream和OutputStream的主要方法
InputStream
int available() //返回此输入流写一个调用可以不受阻塞地从此输入流读取(或跳过)的字节数
void mark(int readlimit) //在此输入流中标记当前位置
void markSupported() //测试此输入流是否支持mark和reset方法
void skip(long n) //跳过和丢弃此输入流中的n个字节
void reset() //将此输入流重新定位到最后一次对此输入流掉哦你个mark方法时的位置
abstract int read() //从输入流中读取单个字节
返回对应读取到的对应字节,当遇到结束时,返回-1
int read(byte[] b) //从输入流中读取一定数量的字节,并将其存储在缓冲区数组b中
int read(byte[] b, in off, int len) //从输入流中读取最多len个字节,并将其存储在b中的指定位置
返回成功读取的字节数,当在开始读取时遇到结束,返回-1
这三个方法同Reader中的read方法一样,都是阻塞的。
OutputStream
- void write(int b) //将指定字节写入此输出流
- void write(buf[] b) //将缓冲区b中的字节写入到此输出流
- void write(buf[] b, int off, int len) //将缓冲区b中指定部分的字节写入到此输出流
- void flush() //刷新此输出流
- void close() //关闭此输出流,在关闭之前,会刷新此输出流
例子的话,参照上面的就可以了
字节字符转换流
在实际应用中,有的时候我们常常需要将字节流转换成字符流,以求更方便高效的处理数据;或者将字符流转换成字节流,来更加仔细的处理数据。InputStreamReader可以将字节流转换成字符流,而OutputStreamWriter可以将字符流转换成字节流。
InputStreamReader
构造方法
- InputStreamReader(InputStream in) //创建一个使用默认字符集的 InputStreamReader
- InputStreamReader(InputStream in, Charset cs)//创建使用给定字符集的 InputStreamReader
- InputStreamReader(InputStream in, CharsetDecoder dec) //创建使用给定字符集解码器的 InputStreamReader
- InputStreamReader(InputStream in, String charsetName)//创建使用指定字符集的 InputStreamReader
方法
除了父类Reader中的方法,InputStreamReader还实现getEncoding方法
- String getEncoding() //返回此流使用的字符编码名称
OutputStreamWriter
构造方法
- OutputStreamWriter(OutputStream out) //创建使用默认字符编码的 OutputStreamWriter
- OutputStreamWriter(OutputStream out, Charset cs) //创建使用给定字符集的 OutputStreamWriter
- OutputStreamWriter(OutputStream out, CharsetEncoding enc)//创建使用给定字符集编码器的 OutputStreamWriter
- OutputStreamWriter(OutputStream out, String charsetName) //创建使用指定字符集的 OutputStreamWriter
方法
除了父类Writer中的方法,OutputStreamReader还实现getEncoding方法
- String getEncoding() //返回此流使用的字符编码名称
文件读写流
在Java的IO中,与文件读写有关的IO类就是FileReader、FileWriter、FileInputStream、FileOutputStream了。
字符流
FileWriter
构造方法
- FileWriter(File file) //根据给定的File对象构造一个FileWriter对象,属于覆盖写入。
- FileWriter(File file, bolean append)//同上,但是多了一个指定是”w”模式还是”a+”模式的参数。
- FileWriter(FileDescriptor fd) //构造与某个文件描述符相关联的FileWriter对象
- FileWriter(String fileName) //通过给定的fileName去创建FileWriter对象
- FileWriter(String fileName, boolean append) //同上
方法
所有方法都是它的父类Writer中的方法,没有新的方法,所以这里略。
FileReader
构造方法
- FileReader(File file) //通过给定的file对象去创建FileReader对象
- FileReader(FileDescriptor fd) //构造与某个文件描述符相关联的FileReader对象
- FileReader(String fileJName) //通过给定的fileName去创建FileReader对象
例子
追加或者覆盖写入指定的内容
1 | import java.io.*; |
字节流
FileInputStream
构造方法
- FileInputStream(File file) //通过打开一个到实际文件的连接来创建一个 FileInputStream,该文件通过文件系统中的 File 对象 file 指定。
- FileInputStream(FileDescriptor fd) //通过使用文件描述符 fd 创建一个 FileInputStream,该文件描述符表示到文件系统中某个实际文件的现有连接。
- FileInputStream(String fileName) //通过fileName去创建一个FileInputStream
方法
除了InputStream类中的方法,FileInputStream还有以下的方法
- protected void finalize() //确保在不再引用的文件输入流时调用其close方法
- FileChannel getChannel() //返回与此文件输入流有关的唯一的FileChannel方法
- FileDescriptor getFD() //返回与此文件输入流有关的唯一的FileDescriptor方法
- String getEncoding() //返回此流使用的字符编码的名称。
FileOutputStream
构造方法
FileOutputStream(File file)
FileOutputStream(File file, boolean append)
FileOutputStream(String fileName)
FileOutputStream(String fileName, boolean append)
FileOutputStream(FileDescriptor fd)
以上构造方法的用法参照FileWriter的即可
方法
除了InputStream类中的方法,FileInputStream还有以下的方法
- protected void finalize() //确保在不再引用的文件输入流时调用其close方法
- FileChannel getChannel() //返回与此文件输入流有关的唯一的FileChannel方法
- FileDescriptor getFD() //返回与此文件输入流有关的唯一的FileDescriptor方法
- String getEncoding() //返回此流使用的字符编码的名称。
三言两语
- FileInputStream和FileOutputStream是最基础的介质流之一(另外一种是ByteArrayOuputStream和ByteArrayInputStream),分别面向文件(和Byte数组)读写数据。
- 文件读写不只用到这几个类,还可以结合其他的类更加方便的从文件中读写数据。比如通过FileReader去构造一个BuferedReader或LineNumberReader对象,在读取数据的时候可以调用readLine()方法来直接读取一个文本行;也可以结合比如Scanner文本扫描器来操作。
字符串读写流
java中的字符串其实在某些方面也可以当作一个字符数组来看待。比如可以通过String[index]的方法来获得某一个位置的字符。当然,也可以使用String.toCharArray()方法来直接获得一个字符数组。而在字符流中,就提供了两个专门为字符串读写所准备的流对象StringReader和StringWriter对象。
在字节流中也有一个是为字符串提供的流对象——StringBufferInputStream,但是在字节流中不应该也不合适这样做,该流对象已过时。
StringReader
构造方法
- StringReader(String s) //基于s创建一个StringReader
方法
StringReader重写了父类Reader中的部分方法,但是作用还是一样的,没有新的方法,所以方法介绍略。
StringWriter
实际上就是把一个StringBuffer对象封装成StringWriter
构造方法
- StringWriter() //使用默认的初始字符串缓冲区大小创建一个StringWriter
- StringWriter(int initialSize) //创建指定缓冲区大小的StringWriter
方法
这里仅介绍父类Reader中没有的方法。
- StringBuffer getBuffer() //返回该字符串缓冲区本身
- String toString() //以字符串的形式返回该缓冲区的当前值
例子
1 | import java.io.*; |
数组读写流
这里仅介绍字符流的,字节流的(ByteArrayInputStream和ByteArrayOutputStream)与之类似,ByteArrayInputStream中的方法和InputStream一样,ByteArrayOutputStream的多出来的方法与CharArrayWriter的类似,多了一个String toString(String charsetName)可以指定编码的而已,所以不介绍字节流的。
CharArrayReader
此类实现一个可用作字符输入流的字符缓冲区。
构造方法
- CharArrayReader(char[] buf) //根据指定的 char 数组创建一个 CharArrayReader
- CharArrayReader(char[]buf, int off, int len) //根据指定的 char 数组创建一个 CharArrayReader
方法
略
CharArrayWriter
此类实现一个可用作 Writer 的字符缓冲区。缓冲区会随向流中写入数据而自动增长。可使用 toCharArray() 和 toString() 获取数据。
在此类上调用 close() 无效,并且在关闭该流后可以调用此类中的各个方法,而不会产生任何 IOException
构造方法
- CharArrayWriter() //创建一个新的 CharArrayWriter
- CharArrayWriter(int initialSize) //创建一个具有指定初始大小的新 CharArrayWriter
方法
- void reset() //重置该缓冲区,从而丢弃输出流中目前已累积的所有输出
- int size() //返回缓冲区的当前大小
- char[] toCharArray() //以字符数据返回输入数据的副本
- String toString() //将输入数据转换成字符串
- void writeTo(Writer out) //将缓冲区的内容写到另一个字符流
缓冲读写流
这里仅介绍字符类的缓冲流,字节类(BufferedInputStream和BufferedOutputStream)的与之相似(构造方法相似,相对于父类InputStream OutputStream,没有额外的方法,比如readLine()或者newLine())
通常情况下,Reader的每个读写请求都会导致低层的字符或字节流进行相应的读写请求,这样子的话,当在进行大量的读写时,这样子无疑是很低效的,开销太大了。比如说,FileReader就好了,如果没有缓冲,每次调用read方法,都会导致从文件中读取字节,然后转换成字符后返回,开销很大。
如果考虑在字符输入输出流中读取文本,然后缓冲各个字符,从而在缓冲区来实现字符、数组、行的高效读写,这无疑是一个很明智的选择。BufferedReader和BufferedWriter就是这样子的。
就像字符串操作时,如果过多的涉及到字符串的拼接,删除等操作时,我们会优先考虑使用StringBuffer,而不是直接使用String。
BufferedReader
构造方法
- BufferedReader(Reader in) //创建一个使用默认大小输入缓冲区的缓冲字符输入流。
- BufferedReader(Reader in, int sz) //创建一个使用指定大小输入缓冲区的缓冲字符输入流。
方法
相对于Reader中的方法,多了一个readLine()方法
- String readLine() //读取一个文本行,如果已到达流末尾,则返回null
BufferedWriter
构造方法
- BufferedWriter(Writer out) //创建一个使用默认大小输出缓冲区的缓冲字符输出流。
- BufferedWriter(Writer out, int sz) //创建一个使用给定大小输出缓冲区的新缓冲字符输出流。
方法
相对于Writer中的方法,多了一个newLine()方法
- void newLine() //写入一个行分割符
不想举例子了,看上面的就好了
管道读写流
线程之间的通信常常也会使用到管道。而在使用管道通信时,一般都是使用配套的PipedWriter和PipedReader或者PipedInputStream和PipedOutputStream,使用之前,必须要先连接到对应的管道流。
字节管道流(PipedInputStream和PipedOutputStream)和字符管道流基本一致,在这里不做而外的解释
PipedReader
构造方法
- PipedReader() //创建尚未连接的 PipedReader
- PipedReader(int pipeSize) //创建一个尚未连接的 PipedReader,并对管道缓冲区使用指定的管道大小
- PipedReader(PipedWriter src) //创建连接到传送 writer src 的 PipedReader
- PipedReader(PipedWriter src, int pipeSize) //创建一个 PipedReader,使其连接到管道 writer src,并对管道缓冲区使用指定的管道大小
方法
相对于Reader中的方法,多了一个connect方法
- void connect(PipedWriter src) //使此传送 reader 连接到传送 writer src
PipedWriter
构造方法
- PipedWriter() //创建一个尚未连接到传送 reader 的传送 writer
- PipedWriter(PipedReader snk) //创建传送 writer,使其连接到指定的传送 reader
方法
相对于Writer中的方法,多了一个connect方法
- void connect(PipedReader snk) //将此传送 writer 连接到接收方
例子
1 | import java.io.*; |
对象读写流
直接将对象作为输入对象或者写入对象的流对象。常用于序列化方面。
ObjectOutputStream
构造方法
- ObjectOutputStream(OutputStream out) //创建写入指定OutputStream的ObjectOutputStream对象
常用方法
void defaultWriteObject() //将当前类的非静态和非瞬态字段写入此流
void close()
void flush()
ObjectOutputStream.PutField putFields() //获取用于缓冲写入流中的持久存储字段的对象
void writeXxx(Xxx val) //将Xxx类型的对象写入
比如writeByte writeChars writeInt等等
void writeObject(Object obj) //将指定的obj对象写入
void writeUTF(String str) //以UTF-8修改版格式写入此String的基本数据
ObjectInputStream
基本上类似于上面的ObjectOutputStream,省略。
例子
1 | import java.io.*; |
过滤读写流
过滤读写流在这里指的是io包里所有以Filter开头的类或者抽象类或者其子类。基本上所有的过滤读写流都算作是装饰流的一种。
在字符流中,有两个,一个是FilterReader,一个是FilterWriter,前者是一个抽象类,有一个直接子类PushbackReader。
FilterReader
抽象类,只是简单的重写了父类Reader中的方法,没有其他的特别的地方。主要作用是作为扩展的时候使用,比如其子类PushbackReader。
FilterWriter
同FilterReader类似,重写了父类Writer的方法。没有子类。
PushbackReader
增加了unread方法,可以回退。
FilterInputStream
重写了父类InputStream的方法,有增强的子类。
LineNumberInputStream
针对行进行读取的一个类,已过时
BufferedInputStream
已在上面说明过了。
DataInputStream
在读取数据的时候,可以更加灵活的读取数据,而不是单单的只有read方法,提供了一系列的readXxx方法
PushbackInputStream
同PushbackReader类似
FilterOutputStream
重写了父类OutputStream的方法,有增强的子类。
BufferedOutputStream
已在上面说明过了
DataOutputStream
在写入数据的时候,可以更加灵活的写入数据,而不是单单的只有write方法,提供了一系列的writeXxx方法
PrintStream
打印输出流,用来装饰其它输出流。它能为其他输出流添加了功能,使它们能够方便地打印各种数据值表示形式。与其他输出流不同,PrintStream 永远不会抛出 IOException;它产生的IOException会被自身的函数所捕获并设置错误标记, 用户可以通过 checkError() 返回错误标记,从而查看PrintStream内部是否产生了IOException。
另外,PrintStream 提供了自动flush 和 字符集设置功能。所谓自动flush,就是往PrintStream写入的数据会立刻调用flush()函数。
PrintWriter和SequenceInputStream
PrintWriter
同PrintStream类似,都是打印输出流。
SequenceInputStream
SequenceInputStream表示其他输入流的逻辑串联。它从输入流的有序集合开始,并从第一个输入流开始读取,直到到达文件末尾,接着从第二个输入流读取,依次类推,直到到达包含的最后一个输入流的文件末尾为止。
构造方法
- SequenceInputStream(Enumeration<? extends InputStream> e) //通过记住参数来初始化新创建的 SequenceInputStream,该参数必须是生成运行时类型为 InputStream 对象的 Enumeration 型参数。
- SequenceInputStream(InputStream s1, InputStream s2) //通过记住这两个参数来初始化新创建的 SequenceInputStream(将按顺序读取这两个参数,先读取 s1,然后读取 s2),以提供从此 SequenceInputStream 读取的字节。
方法
- int available() //返回不受阻塞地从当前底层输入流读取(或跳过)的字节数的估计值,方法是通过下一次调用当前底层输入流的方法。
装饰流和介质流
介质流
介质流指直接连接数据源的流类,如前面介绍的FileInputStream/FileOutputStream和FileReader和FileWriter,该类流直接实现将数据源转换为流对象,在介质流类中实现了流和数据源之间的转换,介质流类均可单独进行使用。
装饰流
装饰流指不直接连接数据源,而是以其它流对象(介质流对象或装饰流对象)为基础建立的流类,该类流实现了将介质流中的数据进行转换,增强流对象的读写能力,比较常用的有DataInputStream/DataOutputStream和BufferedReader/BufferedWriter等,装饰流类不可以单独使用,必须配合介质流或装饰流进行使用。
由于装饰流都是在已有的流对象基础上进行创建的,所以这种创建流的方式被称作“流的嵌套”,通过流的嵌套,可以修饰流的功能,例如使读写的速度增加或者提供更多的读写方式,方便数据格式的处理。
装饰流不改变原来介质流对象中的数据内容,只是从介质流对象基础上创建出的装饰流对象相对于介质流对象进行了一些功能的增强。bu