开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第11天,点击查看活动详情
一、简介
I/O主要解决从数据源读入数据和将数据写入到目的地问题。数据源和目的地可以理解为IO流的两端。(这两端可以是文件或者网络连接)
字节流: InputStream/OutputStream。
字符流: Reader/Writer。
数据源与程序内存读写操作:
二、分类
2.1、按流的方向上
分为输入流InputStream或Reader,输出流OutputStream或Writer
任何从InputStream或Reader派生的类都有read()方法,用于读取单个字节或字节数组。
任何从OutputSteam或Writer派生的类都有write()方法,用于写单个字节或字节数组。
2.2、从操作字节还是操作字符的角度
面向字节流的类,基本都以XxxStream结尾。
面向字符流的类都以XxxReader或XxxWriter结尾。
这两种类型的流是可以转化的,有两个转化流的类,这个后面会说到。
2.3、一般在使用IO流的时候会有下面类似代码:
FileInputStream inputStream = new FileInputStream(new File("a.txt"));
BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream);
这其实是一种装饰器模式的使用,IO流体系中使用了装饰器模式包装了各种功能流类
。
IO流体系中FilterInputStream/FilterOutStream
和FilterReader/FilterWriter
就是装饰器模式的接口类。
从该类向下包装了一些功能流类。有DataInputStream、BufferedInputStream、LineNumberInputStream、PushbackInputStream
等,当然还有输出的功能流类;面向字符的功能流类等。
下面几张图描述了整个IO流的继承体系结构:
InputStream流体系
OutputStream流体系
Reader体系
Writer体系
三、File其实是个工具类
File类其实不止是代表一个文件,它也能代表一个目录下的一组文件(代表一个文件路径)。
File类中最常用的方法:
File.delete() // 删除文件或文件夹目录。
File.createNewFile() // 创建一个新的空文件。
File.mkdir() // 创建一个新的空文件夹。
File.list() // 获取指定目录下的文件和文件夹名称。
File.listFiles() // 获取指定目录下的文件和文件夹对象。
File.exists() // 文件或者文件夹是否存在
String getAbsolutePath() // 获取绝对路径
long getFreeSpace() // 返回分区中未分配的字节数。
String getName() // 返回文件或文件夹的名称。
String getParent() // 返回父目录的路径名字符串;如果没有指定父目录,则返回 null。
File getParentFile() // 返回父目录File对象
String getPath() // 返回路径名字符串。
long getTotalSpace() // 返回此文件分区大小。
long getUsableSpace() //返回占用字节数。
int hashCode() //文件哈希码。
long lastModified() // 返回文件最后一次被修改的时间。
long length() // 获取长度,字节数。
boolean canRead() //判断是否可读
boolean canWrite() //判断是否可写
boolean isHidden() //判断是否隐藏
// 成员函数
static File[] listRoots() // 列出可用的文件系统根。
boolean renameTo(File dest) // 重命名
boolean setExecutable(boolean executable) // 设置执行权限。
boolean setExecutable(boolean executable, boolean ownerOnly) // 设置其他所有用户的执行权限。
boolean setLastModified(long time) // 设置最后一次修改时间。
boolean setReadable(boolean readable) // 设置读权限。
boolean setReadable(boolean readable, boolean ownerOnly) // 设置其他所有用户的读权限。
boolean setWritable(boolean writable) // 设置写权限。
boolean setWritable(boolean writable, boolean ownerOnly) // 设置所有用户的写权限。
需要注意的是,不同系统对文件路径的分割符表是不一样的,比如Windows中是“\”,Linux是“/”。
而File类给我们提供了抽象的表示File.separator,屏蔽了系统层的差异。因此平时在代码中不要使用诸如“\”这种代表路径,可能造成Linux平台下代码执行错误。
示例:根据传入的规则,遍历得到目录中所有的文件构成的File对象数组
public class Directory {
public static File[] getLocalFiles(File dir, final String regex){
// dir.listFiles(FilenameFilter ) 是策略模式的一种实现,
// 而且使用了匿名内部类的方式。
return dir.listFiles(new FilenameFilter() {
private Pattern pattern = Pattern.compile(regex);
public boolean accept(File dir, String name) {
return pattern.matcher(new File(name).getName()).matches();
}
});
}
// 重载方法
public static File[] getLocalFiles(String path, final String regex){
return getLocalFiles(new File(path),regex);
}
public static void main(String[] args) {
String dir = "d:";
File[] files = Directory.getLocalFiles(dir,".*\\.txt");
for(File file : files){
System.out.println(file.getAbsolutePath());
}
}
}
// 输出结果:
d:\\1.txt
d:\\新建文本文档.txt
四、InputStream和OutputStream
4.1、InputStream从数据源对象中将数据读入程序内容。
通过看InputStream的源码,可以看出它是一个抽象类:
public abstract class InputStream extends Object implements Closeable{}
提供了一些基础的输入流方法:
//从数据中读入一个字节,并返回该字节,遇到流的结尾时返回-1
abstract int read()
//读入一个字节数组,并返回实际读入的字节数,最多读入b.length个字节,遇到流结尾时返回-1
int read(byte[] b)
// 读入一个字节数组,返回实际读入的字节数或者在碰到结尾时返回-1.
//b:代表数据读入的数组, off:代表第一个读入的字节应该被放置的位置在b中的偏移量,len:读入字节的最大数量
int read(byte[],int off,int len)
// 返回当前可以读入的字节数量,如果是从网络连接中读入,这个方法要慎用,
int available()
//在输入流中跳过n个字节,返回实际跳过的字节数
long skip(long n)
//标记输入流中当前的位置
void mark(int readlimit)
//判断流是否支持打标记,支持返回true
boolean markSupported()
// 返回最后一个标记,随后对read的调用将重新读入这些字节。
void reset()
// 关闭输入流,这个很重要,流使用完一定要关闭
void close()
直接从InputStream继承的流,基本上对应了每种数据源类型。
类 | 功能 |
---|---|
ByteArrayInputStream | 将字节数组作为InputStream |
StringBufferInputStream | 将String转成InputStream |
FileInputStream | 从文件中读取内容 |
PipedInputStream | 产生用于写入相关PipedOutputStream的数据。实现管道化 |
SequenceInputStream | 将两个或多个InputStream对象转换成单一的InputStream |
FilterInputStream | 抽象类,主要是作为“装饰器”的接口类,实现其他的功能流 |
4.2、OutputStream将程序内存中的数据写入到接收数据的一端。
public abstract class OutputStream implements Closeable, Flushable {}
提供了基础方法相比输入流来说简单多了,主要就是write写方法(几种重载的方法)、flush冲刷和close关闭。
// 写出一个字节的数据
abstract void write(int n)
// 写出字节到数据b
void write(byte[] b)
// 写出字节到数组b,off:代表第一个写出字节在b中的偏移量,len:写出字节的最大数量
void write(byte[] b, int off, int len)
//刷新输出流,也就是将所有缓冲的数据发送到目的地
void flush()
// 关闭输出流
void close()
同样地,OutputStream
也提供了一些基础流的实现,这些实现也可以和特定的目的地(接收端)对应起来,比如输出到字节数组或者是输出到文件/管道等。
类 | 功能 |
---|---|
ByteArrayOutputStream | 在内存中创建一个缓冲区,所有送往“流”的数据都要放在此缓冲区 |
FileOutputStream | 将数据写入文件 |
PipedOutputStream | 和PipedInputStream配合使用。实现管道化 |
FilterOutputStream | 抽象类,主要是作为“装饰器”的接口类,实现其他的功能流 |