IO流在java中存在的本质是用来进行数据的传输。其中按照流的方向分为:输入流和输出流;按照数据处理的单位分为:字节流和字符流。(字符是无符号类型,字节是有符号类型)。
本文将分别讨论输入流、输出流、字节流和字符流。
一、以字节为单位的输入流的框架图:
从图中可以看出以字节为单位的输入流的公共父类是InputStream:
(1) InputStream是以字节为单位的输入流超类,提供了接口从输入流中读取字节数据。
(2) ByteArrayInputStream是字节数组输入流,它的内部缓冲区是一个字节数组,本质是通过字节数组来实现的。
(3) BufferedInputStream是缓冲输入流,作用是为另一个输入流添加缓冲功能。
(4) FileInputStream是文件输入流,通常用于对文件进行读取操作。
(5) ObjectInputStream是对象输入流,和ObjectOutputStream一起来对基本数据或对象进行持久存储。
(6) PipedInputStream是管道输入流,能够实现多线程间的管道通信。
(7) DataInputStream是数据输入流,用来装饰其他输入流,允许应用程序以与机器无关方式从底层输入流中读取基本Java数据类型。
(8) FileDescriptor是文件描述符,用来表示开放文件,开放套接字等。
二、以字节为单位的输出流的框架图:
从中我们可以看出,以字节为单位的输出流的公共父类是OutputStream:
从中我们可以看出,以字节为单位的输出流的公共父类是OutputStream:
(1)OutputStream是以字节为单位的输出流的超类,提供了write()函数从输出流中读取字节数据。
(2)ByteArrayOutputStream是字节数组输出流,写入ByteArrayOutputStream的数据被写入到一个byte数组,缓冲区会随着数据的不断写入而自动增长,可使用toByteArray()和toString()获取数据。
(3)PipedOutputStream是管道输出流,和PipedInputStream一起使用,能实现多线程间的管道通信。
(4)FilterOutputStream是过滤输出流,是DataOutputStream,BufferedOutputStream和PrintStream的超类
(5)DataOutputStream是数据输出流,用来装饰其他的输出流,允许应用程序以与机器无关方式向底层写入基本Java数据类型。
(6)BufferedOutputStream是缓冲输出流,它的作用是为另一个输出流添加缓冲功能。
(7)PrintStream是打印输出流,用来装饰其他输出流,为其他输出流添加功能,方便的打印各种数据值
(8)FileOutputStream是文件输出流,通常用于向文件进行写入操作。
(9)ObjectOutputStream是对象输出流,它和ObjectInputStream一起对基本数据或者对象的持久存储。
输入流和输出流都有对应的关系,如图:
三、字节转换为字符流的框架图
在java中,字节流能转换为字符流,转换关系图
从上图可以看出:
(1)FileReader继承于InputStreamReader,而InputStreamReader依赖于InputStream,因为InputStreamReader的构造函数是以InputStream为参数,传人InputStream会在InputStreamReader内部通过转码,将字节转换成字符。
(2)FileWriter继承于OutputStreamWriter,而OutStreamWriter依赖于OutputStream,因为OutputStreamWriter的构造函数是以OutputStream为参数,我们传人OutputStream会在OutputStreamWriter内部通过转码,将字节转换成字符。字节转换为字符流的框架图
在java中,字节流能转换为字符流,转换关系图
从上图可以看出:
(1)FileReader继承于InputStreamReader,而InputStreamReader依赖于InputStream,因为InputStreamReader的构造函数是以InputStream为参数,传人InputStream会在InputStreamReader内部通过转码,将字节转换成字符。
(2)FileWriter继承于OutputStreamWriter,而OutStreamWriter依赖于OutputStream,因为OutputStreamWriter的构造函数是以OutputStream为参数,我们传人OutputStream会在OutputStreamWriter内部通过转码,将字节转换成字符。
附上源码:
基于JDK8的InputStream类源码:
public abstract class InputStream implements Closeable {
//最大跳过的缓冲区大小
private static final int MAX_SKIP_BUFFER_SIZE = 2048;
//从输入的流中读取下一个字节
public abstract int read() throws IOException;
//从输入流中读取一定大小的字节,没有数据返回-1
public int read(byte b[]) throws IOException {
return read(b, 0, b.length);
}
//从输人流中读取的数据放到b数组中起始位置为off,长度为len
public int read(byte b[], int off, int len) throws IOException {
if (b == null) {
throw new NullPointerException();
} else if (off < 0 || len < 0 || len > b.length - off) {
throw new IndexOutOfBoundsException();
} else if (len == 0) {
return 0;
}
int c = read();
if (c == -1) {
return -1;
}
b[off] = (byte)c;
int i = 1;
try {
for (; i < len ; i++) {
c = read();
if (c == -1) {
break;
}
b[off + i] = (byte)c;
}
} catch (IOException ee) {
}
return i;
}
//跳过输入流的长度为n字节
public long skip(long n) throws IOException {
long remaining = n;
int nr;
if (n <= 0) {
return 0;
}
int size = (int)Math.min(MAX_SKIP_BUFFER_SIZE, remaining);
byte[] skipBuffer = new byte[size];
while (remaining > 0) {
nr = read(skipBuffer, 0, (int)Math.min(size, remaining));
if (nr < 0) {
break;
}
remaining -= nr;
}
return n - remaining;
}
//返回从输入流中可以读取的数据
public int available() throws IOException {
return 0;
}
//关闭输入流,释放任何与这个流有关的资源
public void close() throws IOException {}
//标记在这个输入流的当前位置
public synchronized void mark(int readlimit) {}
//返回到最近标记的位置
public synchronized void reset() throws IOException {
throw new IOException("mark/reset not supported");
}
//测试这个输入流是否支持标记或者重置方法
public boolean markSupported() {
return false;
}
}
基于JDK8的OutputStream类源码:
public abstract class OutputStream implements Closeable, Flushable {
//写特定的字节到输出流
public abstract void write(int b) throws IOException;
//写特定的长度的字节数组到输出流中
public void write(byte b[]) throws IOException {
write(b, 0, b.length);
}
//从b数组中,起始值为off,长度为len的数据到输出流中
public void write(byte b[], int off, int len) throws IOException {
if (b == null) {
throw new NullPointerException();
} else if ((off < 0) || (off > b.length) || (len < 0) ||
((off + len) > b.length) || ((off + len) < 0)) {
throw new IndexOutOfBoundsException();
} else if (len == 0) {
return;
}
for (int i = 0 ; i < len ; i++) {
write(b[off + i]);
}
}
//刷新输出流,强制任意的缓冲输出都被输出
public void flush() throws IOException {
}
//关闭输出流,释放与这个输出流相关的所有系统资源
public void close() throws IOException {
}
}
File是“文件”和“目录路径名”的抽象表示形式。File之间继承Object,实现了Serializable和Comparable接口,因此文件支持File对象序列化,同时File对象之间可以比较大小。
File类中主要的函数有:
// 静态成员
public static final String pathSeparator // 路径分割符":"
public static final char pathSeparatorChar // 路径分割符':'
public static final String separator // 分隔符"/"
public static final char separatorChar // 分隔符'/'
// 构造函数
File(File dir, String name)
File(String path)
File(String dirPath, String name)
File(URI uri)
// 成员函数
boolean canExecute() // 测试应用程序是否可以执行此抽象路径名表示的文件。
boolean canRead() // 测试应用程序是否可以读取此抽象路径名表示的文件。
boolean canWrite() // 测试应用程序是否可以修改此抽象路径名表示的文件。
int compareTo(File pathname) // 按字母顺序比较两个抽象路径名。
boolean createNewFile() // 当且仅当不存在具有此抽象路径名指定名称的文件时,不可分地创建一个新的空文件。
static File createTempFile(String prefix, String suffix) // 在默认临时文件目录中创建一个空文件,使用给定前缀和后缀生成其名称。
static File createTempFile(String prefix, String suffix, File directory) // 在指定目录中创建一个新的空文件,使用给定的前缀和后缀字符串生成其名称。
boolean delete() // 删除此抽象路径名表示的文件或目录。
void deleteOnExit() // 在虚拟机终止时,请求删除此抽象路径名表示的文件或目录。
boolean equals(Object obj) // 测试此抽象路径名与给定对象是否相等。
boolean exists() // 测试此抽象路径名表示的文件或目录是否存在。
File getAbsoluteFile() // 返回此抽象路径名的绝对路径名形式。
String getAbsolutePath() // 返回此抽象路径名的绝对路径名字符串。
File getCanonicalFile() // 返回此抽象路径名的规范形式。
String getCanonicalPath() // 返回此抽象路径名的规范路径名字符串。
long getFreeSpace() // 返回此抽象路径名指定的分区中未分配的字节数。
String getName() // 返回由此抽象路径名表示的文件或目录的名称。
String getParent() // 返回此抽象路径名父目录的路径名字符串;如果此路径名没有指定父目录,则返回 null。
File getParentFile() // 返回此抽象路径名父目录的抽象路径名;如果此路径名没有指定父目录,则返回 null。
String getPath() // 将此抽象路径名转换为一个路径名字符串。
long getTotalSpace() // 返回此抽象路径名指定的分区大小。
long getUsableSpace() // 返回此抽象路径名指定的分区上可用于此虚拟机的字节数。
int hashCode() // 计算此抽象路径名的哈希码。
boolean isAbsolute() // 测试此抽象路径名是否为绝对路径名。
boolean isDirectory() // 测试此抽象路径名表示的文件是否是一个目录。
boolean isFile() // 测试此抽象路径名表示的文件是否是一个标准文件。
boolean isHidden() // 测试此抽象路径名指定的文件是否是一个隐藏文件。
long lastModified() // 返回此抽象路径名表示的文件最后一次被修改的时间。
long length() // 返回由此抽象路径名表示的文件的长度。
String[] list() // 返回一个字符串数组,这些字符串指定此抽象路径名表示的目录中的文件和目录。
String[] list(FilenameFilter filter) // 返回一个字符串数组,这些字符串指定此抽象路径名表示的目录中满足指定过滤器的文件和目录。
File[] listFiles() // 返回一个抽象路径名数组,这些路径名表示此抽象路径名表示的目录中的文件。
File[] listFiles(FileFilter filter) // 返回抽象路径名数组,这些路径名表示此抽象路径名表示的目录中满足指定过滤器的文件和目录。
File[] listFiles(FilenameFilter filter) // 返回抽象路径名数组,这些路径名表示此抽象路径名表示的目录中满足指定过滤器的文件和目录。
static File[] listRoots() // 列出可用的文件系统根。
boolean mkdir() // 创建此抽象路径名指定的目录。
boolean mkdirs() // 创建此抽象路径名指定的目录,包括所有必需但不存在的父目录。
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 setReadOnly() // 标记此抽象路径名指定的文件或目录,从而只能对其进行读操作。
boolean setWritable(boolean writable) // 设置此抽象路径名所有者写权限的一个便捷方法。
boolean setWritable(boolean writable, boolean ownerOnly) // 设置此抽象路径名的所有者或所有用户的写权限。
String toString() // 返回此抽象路径名的路径名字符串。
URI toURI() // 构造一个表示此抽象路径名的 file: URI。
URL toURL() // 已过时。 此方法不会自动转义 URL 中的非法字符。建议新的代码使用以下方式将抽象路径名转换为 URL:首先通过 toURI 方法将其转换为 URI,然后通过 URI.toURL 方法将 URI 装换为 URL。
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
File常用的方法:
一、创建目录常用的方法
(1)根据相对路径创建目录
[java] view plain copy
print?
File dir = new File("dir");
dir.mkdir();//在当前目录下创建目录
(2)根据绝对路径创建目录
[java] view plain copy
print?
File dir = new File("/home/skywang/dir");
dir.mkdirs();
(3)URI方法
[java] view plain copy
print?
URI uri = new URI("file:/home/skywang/dir");
File dir = new File(uri);
dir.mkdir();
二、新建子目录几种常用方法
(1)在当前子目录下创建一个目录
[java] view plain copy
print?
File sub1 = new File("dir", "sub1");//目录dir必须是存在的
sub1.mkdir();
(2)通过目录创建目录
[java] view plain copy
print?
File sub3 = new File("dir/sub3");//dir不一定存在,当不存在时会创建
sub3.mkdirs();
(3)绝对目录创建目录
[java] view plain copy
print?
File sub4 = new File("/home/skywang/dir/sub4");//当目录不存在时会创建
sub4.mkdirs();
(4)URI方式
[java] view plain copy
print?
URI uri = new URI("file:/home/skywang/dir/sub5");//和(3)一样,目录不存在就创建
File sub5 = new File(uri);
sub5.mkdirs();
三、新建文件的常用方法
(1)在当前子目录下创建文件
[java] view plain copy
print?
try {
File dir = new File("dir"); // 获取目录“dir”对应的File对象
File file1 = new File(dir, "file1.txt");
file1.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
(2)相对目录下创建文件
[java] view plain copy
print?
try {
File file2 = new File("dir", "file2.txt");
file2.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
(3)绝对路径创建文件
[java] view plain copy
print?
try {
File file3 = new File("/home/skywang/dir/file3.txt");
file3.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
(4)URI方式创建文件
[java] view plain copy
print?
try {
URI uri = new URI("file:/home/skywang/dir/file4.txt");
File file4 = new File(uri);
file4.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}