通过数据流、序列化和文件系统为系统提供输入和输出。除非特别说明,否则对应java.io包中的类来说,传递一个null作为构造器的参数必定会引发NullPointException
。
接口
- AutoCloseable
- Closeable:可以别关闭的数据流源头或数据流终点
- DataInput:DataInput接口提供从二进制流中读取字节并从中重构任何Java原生类型的数据。
- DataOutput:DataOutput接口提供任意Java原生类型转化成为一系列的字节数据并将这些字节写入到二进制流
- FileFilter
- FilenameFilter
- Flushable
- ObjectInput
- ObjecuOutput
- ObjectStreamConstants
- Serializable
-
类
BufferedInputStream
- BufferedOutputStream
- BufferedReader
- BufferedWriter
- ByteArrayInputStream
- ByteArrayOutputStream
- CharArrayReader
- CharArrayWriter
- Console
- DataInputStream
- DataOutputStream
- File
- FileDescriptor
- FileInputStream
- FileOutputStream
- FilePermission
- FileReader
- FileWriter
- FilterInputStream
- FilterOutputStream
- FilterReader
- FilterWriter
- InputStream
- InputStreamReader
- LineNumberInputStream
- LineNumberReader
- ObjectInputStream
- ObjectInputStream.GetField
- ObjectOutputStream
- ObjectOutputStream.GetField
- ObjectStreamClass
- ObjectStreamField
- OutputStream
- OutputStreamWriter
- PipedInputStream
- PipedOutputStream
- PipedReader
- PipedWriter
- PrintStream
- PrintWriter
- PushbackInputStream
- PushbackReader
- RandomAccessFile
- Reader
- SequenceInputStream
- SerializablePermission
- StreamTokenizer
- StringBufferInputStream
- StringReader
- StringWriter
- Writer
Closeable
```java
/**
- Closeable是一个能够被关闭的数据源。close()方法用来释放资源 *
@since 1.5 */ public interface Closeable extends AutoCloseable {
/**
- 关闭流并且释放其持有的系统资源。如果流已经关闭,调用该方法无任何影响。
- 如 AutoCloseable#close() 中所述,关闭可能失败的情况需要小心。
- 强烈建议在抛出IOException之前,放弃底层资源并在内部将Closeable标记为closed。 *
- @throws IOException if an I/O error occurs
*/
public void close() throws IOException;
}
获取可以从该输入流读取(或跳过)的字节数。多字节的单词读取或跳过不会阻塞,但是可能一次只能读到或跳过部分数据。<a name="KT3AI"></a>
# InputStream
输入字节流的基类。其子类必须提供一个返回下一个输入字节的方法。<br />**
<a name="Tt7zi"></a>
## available
```java
public int available() throws IOException {
return 0;
}
注意:虽然InputStream的某些子类将该方法实现为返回流中的字节总数,但大多数子类不是这种实现方式。使用此方法的返回值来分配保存该流中所有数据的缓冲区大小永远是不正确的。
close
public void close() throws IOException {}
关闭输入流并释放系统资源
mark
public synchronized void mark(int readlimit) {}
标记输入流当前的位置。随后调用reset
方法重新定位在最后标记的位置,以便后续的读取操作能够读取相同的字节。
readlimit
参数表示在标记失效之前还能从流里读取的字节数。
mark
的一般约定是:如果markSupported
方法返回true,那么流以某种方式记住调用mark
后读取的所有字节,并随时准备在调用方法reset
时再次提供这些字节。但是,如果在调用reset
之前从流中读取的字节数超过readlimit
,那么流不会记住任何数据。
这句话的意思是说:mark就像书签一样,用于标记,以后再调用reset时就可以再回到这个mark过的地方。mark方法有个参数,通过这个整型参数,你告诉系统,希望在读出这么多个字符之前,这个mark保持有效。比如说mark(10),那么在read()10个以内的字符时,reset()操作后可以重新读取已经读出的数据,如果已经读取的数据超过10个,那reset()操作后,就不能正确读取以前的数据了,因为此时mark标记已经失效。
标记一个已关闭的流不应对流产生任何影响。
markSupport
public boolean markSupported() {
return false;
}
输入流是否支持mark
和reset
方法
reset
public synchronized void reset() throws IOException {
throw new IOException("mark/reset not supported");
}
重定位流到最后一次调用mark
方法标记的位置。
reset
的一般约定如下:
- 如果MarkSupport方法返回true:
- 如果mark方法至流被创建之后就没有别调用,或者读取的字节数大于上一次调用mark方法时传入的参数,该方法将抛出IOException;
- 如果没有抛出这样的IOException,那么流将被重置为这样一种状态:自最近一次调用mark(或者自文件开始以来,如果mark没有被调用)以来读取的所有字节都将被重新提供给后续的 read方法调用,后跟任何从调用 reset 时起将作为下一输入数据的字节
如果MarkSupport方法返回false:
- 如果未抛出 IOException,则将该流重新设置为一种固定状态,该状态取决于输入流的特定类型及其创建方式。提供给 read 方法后续调用者的字节取决于特定类型的输入流。
除了抛出 IOException 之外,类 InputStream 的方法 reset 不执行任何操作。
skip
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;
}
从输入流中读取或跳过n个字节。由于各种原因,skip方法每次可能只会跳过较少的字节数,有可能是0(这也是使用while循环的原因)。这可能是由许多条件中的任何一种造成的;在跳过n个字节之前到达文件末尾只是一种可能性。
返回跳过的实际字节数。如果n为负,则类InputStream的skip方法始终返回0,并且不跳过任何字节。子类处理负值的方式可能不同。
read
public abstract int read() throws IOException;
从输入流中读取下一个字节。读取的字节数值是作为一个int(0-255)类型返回的。如果已经读到流的末尾则返回-1。在读取到下一个字节、检测到流的末尾或抛出异常之前,这个方法是阻塞的。
**
read
public int read(byte b[]) throws IOException {
return read(b, 0, b.length);
}
从输入流中读取一定数量的字节并存储在byte数组中。实际读取到的字节数量作为一个int类型返回。在输入流可读取、检测到流的末尾或抛出异常之前,这个方法是阻塞的。
**
如果参数b
的长度为0,不会读取任何字节并且返回0。如果因为输入流已经处在文件末尾导致没能读到任何字节,将返回-1.
read
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;
}
内部使用read()无参方法实现,循环n次,每次读取一个字节。
尝试读取len
个字节,但是真实读到的字节数有可能小于len,真正读到的字节数作为一个int类型返回。
在输入流可读取、检测到流的末尾或抛出异常之前,这个方法是阻塞的。
**
FileInputStream
文件输入流,需要一个传入一个被读取的文件。
ByteArrayInputStream
内部有一个byte[]类型的buffer,存储可以从这个流中读取的字节数据。还有一个内部的计数器追踪可以被read方法读取的下一个字节。
该类的所有方法都不会发生IOException。
ObjectInputStream
实现序列化。
StringBufferInputStream
此类可以创建一个字符串内容的字节流。也可以使用ByteArrayInputStream从字节数组中读取字节。
OutputStream
输出字节流的抽象基类,其所有子类都需要提供一个能够写一个字节的方法。
Close
public void close() throws IOException {
}
关闭输出流并且释放系统资源。已经关闭的输出流不能够在执行写操作,且不能够再次重新打开。
flush
public void flush() throws IOException {
}
刷新输出流并且强制一些缓存的字节被写出。flush的一般约定是:如果先前写入的字节已被OutputStream的实现缓冲,则应立即将这些字节写入其预期目的地。
如果该流的预期目的地是底层操作系统提供的抽象,例如文件,则刷新该流仅保证先前写入该流的字节被传递到操作系统以进行写入;它不能保证它们确实被写入到物理设备(如磁盘驱动器)中。
write
public abstract void write(int b) throws IOException;
写一个字节到输出流。写入的是b
的低8位,高24位自动忽略。
write
public void write(byte b[]) throws IOException {
write(b, 0, b.length);
}
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(int)实现
write(b[off + i]);
}
}
从字节数组中由off
位置开始写入len
个字节到输出流。
可能触发IOException
、NullPointException
以及IndexOutofException
。
Reader
输入字节流的抽象基类。子类必须实现read(char[], int, int)
和close()
方法。注意,大多数子类会重写该类中定义的一些方法,以便提供更高的效率和/或附加功能。
ready
public boolean ready() throws IOException {
return false;
}
该字节流是否已准备就绪,可以开始读取数据。
如果保证下一次read()
不阻塞输入,则为true,否则为false。请注意,返回false并不保证下一次读取将被阻塞。
close
abstract public void close() throws IOException;
关闭输入流并释放系统资源。一旦一个输入流关闭,再调用read()
、ready()
、mark()
、reset()
或者 skip()
等方法会抛出IOException
。
markSupport
public boolean markSupported() {
return false;
}
输入流是否支持mark
操作。
mark
public void mark(int readAheadLimit) throws IOException {
throw new IOException("mark() not supported");
}
标记当前留的位置,调用reset()
方法之后将重置流的位置到该标记点。
skip
public long skip(long n) throws IOException {
if (n < 0L)
throw new IllegalArgumentException("skip value is negative");
int nn = (int) Math.min(n, maxSkipBufferSize);
synchronized (lock) {
if ((skipBuffer == null) || (skipBuffer.length < nn))
skipBuffer = new char[nn];
long r = n;
while (r > 0) {
int nc = read(skipBuffer, 0, (int)Math.min(r, nn));
if (nc == -1)
break;
r -= nc;
}
return n - r;
}
}
跳过字节。该方法会阻塞直到有字符可以被读取,或发生IO错误,或已经读到留的末端。
read
public int read() throws IOException {
char cb[] = new char[1];
if (read(cb, 0, 1) == -1)
return -1;
else
return cb[0];
}
读取单个字节。该方法会阻塞直到有字符可以被读取,或发生IO错误,或已经读到留的末端。
读取到的字符将被转换成为int类型数据返回。如果已经读到流的末端,将返回-1.
public int read(char cbuf[]) throws IOException {
return read(cbuf, 0, cbuf.length);
}
读取字符并存放在数组中。该方法会阻塞直到有字符可以被读取,或发生IO错误,或已经读到留的末端。
返回值表示读取到的字符数量,返回-1表示已经到了流的末端。
abstract public int read(char cbuf[], int off, int len) throws IOException;
读取字符并存入数组的部分空间,该方法会阻塞直到有字符可以被读取,或发生IO错误,或已经读到留的末端。
Writer
用于写入字符流的抽象基类。子类必须实现的方法只有write(char[]、int、int)
、flush()
和close()
。然而,大多数子类会重写别的一些方法,以便提供更高的效率和/或附加功能。
append
public Writer append(char c) throws IOException {
write(c);
return this;
}
将指定的字符追加到次输出流。
public Writer append(CharSequence csq) throws IOException {
if (csq == null)
write("null");
else
write(csq.toString());
return this;
}
将指定的字符序列追加到次输出流。
public Writer append(CharSequence csq, int start, int end) throws IOException {
CharSequence cs = (csq == null ? "null" : csq);
write(cs.subSequence(start, end).toString());
return this;
}
将指定字节序列的start-end子序列追加到输出流。
close
abstract public void close() throws IOException;
关闭流并释放系统资源。一旦流关闭之后,再调用write()
或 flush()
将抛出IOException。
flush
abstract public void flush() throws IOException;
刷新流。如果流已将write()
方法写入的任何字符保存在缓冲区中,则立即将它们写入目标。如果目标是另一个字符或字节流,则立即刷新它。因此,一次flush()
调用将刷新写入程序和输出流链中的所有缓冲区。
如果该流的预期目的地是底层操作系统提供的抽象,例如文件,则刷新该流仅保证先前写入该流的字节被传递到操作系统以进行写入;它不能保证它们确实被写入到物理设备(如磁盘驱动器)中。
write
public void write(int c) throws IOException {
synchronized (lock) {
if (writeBuffer == null){
writeBuffer = new char[WRITE_BUFFER_SIZE];
}
writeBuffer[0] = (char) c;
write(writeBuffer, 0, 1);
}
}
写入的是低16位(chat->16位,int->32位)
public void write(char cbuf[]) throws IOException {
write(cbuf, 0, cbuf.length);
}
abstract public void write(char cbuf[], int off, int len) throws IOException;
写出字符数组。
public void write(String str) throws IOException {
write(str, 0, str.length());
}
public void write(String str, int off, int len) throws IOException {
synchronized (lock) {
char cbuf[];
if (len <= WRITE_BUFFER_SIZE) {
if (writeBuffer == null) {
writeBuffer = new char[WRITE_BUFFER_SIZE];
}
cbuf = writeBuffer;
} else { // Don't permanently allocate very large buffers.
cbuf = new char[len];
}
str.getChars(off, (off + len), cbuf, 0);
write(cbuf, 0, len);
}
}
写入String。内部将String转换成为字符数组写入。
File
文件和目录路径名称的抽象表示。
用户接口或操作系统使用依赖系统的路径名称字符串来表示一个文件和目录。此类表示一个抽象、独立于系统的路径名层级视图。一个抽象的路径名包含两个部分:
- 一个可选的、依赖于系统的前缀字符串,例如,作为硬盘标识符,
"/"
表示UNIX根目录,"\\\\"
表示Windows UNC路径名等。 - 零至多个字符串名称序列。
抽象路径名中的first name
可以是目录名,如果是Microsoft Windows UNC路径名,则可以是主机名。抽象路径名中的每个后续名称表示一个目录;last name
可以表示一个目录或一个文件。空的抽象路径名没有前缀和空的名称序列。
路径名字符串与抽象路径名之间的转换本质上依赖于系统。当抽象路径名转换为路径名字符串时,每个名称都用默认分隔符来分隔。默认名称分隔符由系统属性定义文件分隔符,并在此类的公共静态字段separator
和separatorChar
中可用。将路径名字符串转换为抽象路径名时,其中的名称可以用默认名称分隔符或基础系统支持的任何其他名称分隔符分隔。
路径名,无论是抽象的还是字符串形式的,可以是绝对的,也可以是相对的。绝对路径名是完整的,因为不需要其他信息来定位它所表示的文件。相反,相对路径名必须根据从其他路径名获取的信息进行解释。默认情况下java.io
文件包始终根据当前用户目录解析相对路径名。此目录由系统属性命名用户.dir
,并且通常是调用Java
虚拟机的目录。
抽象路径名的父级可以通过调用此类的getParent()
方法获得,它由路径名的前缀和路径名的名称序列中的每个名称(最后一个除外)组成。每个目录的绝对路径名都是具有以目录绝对路径名开头的绝对抽象路径名的任何文件对象的祖先。例如,抽象路径名“/usr”
表示的目录是路径名“/usr/local/bin”
表示的目录的祖先。
前缀概念用于处理UNIX
平台上的根目录,以及Microsoft Windows
平台上的驱动器说明符、根目录和UNC
路径名,如下所示:
- 对于UNIX系统,绝对路径的前缀始终是
"/"
。相对路径不存在前缀。根目录的抽象路径名由前缀"/"
和一个空名称序列组成; - 对于Windows平台而言,包含驱动器(C、D、E盘等)说明符的路径名的前缀由驱动器号后跟
**“:”**
组成,如果路径名是绝对的,则可能后跟“\\”
。UNC路径名的前缀是“\\\”
;主机名和共享名是名称序列中的前两个名称。不指定驱动器的相对路径名没有前缀
此类的实例可能表示也可能不表示实际的文件系统对象,例如文件或目录。如果它确实表示这样一个对象,那么该对象驻留在一个分区中。分区是文件系统特定于操作系统的存储部分。单个存储设备(例如,物理磁盘驱动器、闪存、CD-ROM)可以包含多个分区。对象(如果有)将驻留在由该路径名的绝对形式的某个祖先命名的分区上。
文件系统可以实现对实际文件系统对象上的某些操作的限制,例如读取、写入和执行。这些限制统称为访问权限。文件系统可能对单个对象具有多组访问权限。例如,一个集合可以应用于对象的所有者,另一个集合可以应用于所有其他用户。对象的访问权限可能会导致此类中的某些方法失败。
File类的实例是不可变的;也就是说,一旦创建,由File对象表示的抽象路径名将永远不会更改。
与 java.nio.file
包的互操作性java.nio.file
包定义Java虚拟机访问文件、文件属性和文件系统的接口和类。这个API可以用来解除java.io.File
类的限制。toPath
方法可用于获得使用由文件对象表示的抽象路径来定位文件的路径。结果路径可与Files类一起使用,以提供对附加文件操作、文件属性和I/O异常的更有效和更广泛的访问,从而在文件操作失败时帮助诊断错误。
在Android上,当向操作系统发送文件名时,字符串被转换为UTF-8字节序列,操作系统返回的字节序列(来自各种列表方法)通过将其解码为UTF-8字节序列被转换为字符串。
pathSeparatorChar
public static final char pathSeparatorChar = fs.getPathSeparator();
依赖与系统的路径分隔符。此字段初始化为包含系统属性值的第一个字符路径分隔符. 此字符用于分隔作为路径列表给定的文件序列中的文件名。在UNIX系统上,此字符是“:”;在Microsoft Windows系统上,此字符是“;”。
pathSeparator
public static final String pathSeparator = "" + pathSeparatorChar;
SeparatorChar
public static final char separatorChar = fs.getSeparator();
依赖于系统的默认名称分隔符。此字段初始化为包含系统属性值的第一个字符文件分隔符. 在UNIX系统上,此字段的值为**“/”**
;在Microsoft Windows系统上,此字段的值为**“\\”**
。
**
Separator
public static final String separator = "" + separatorChar;
SeparatorChar
的字符串形式。
System.out.println(File.separator);
System.out.println(File.pathSeparatorChar);
Android平台运行: / :
File file = new File("////..\\index.txt");
getName
public String getName() {
int index = path.lastIndexOf(separatorChar);
if (index < prefixLength) return path.substring(prefixLength);
return path.substring(index + 1);
}
返回文件或文件夹的路径名称,仅返回路径名序列的last name
。
System.out.println(imageFile.getName()); // ..\index.txt
getPath
public String getPath() {
return path;
}
将抽象路径(定义File时传入的路径,也就是说,你传入什么路径,就返回什么路径)转化为路径名字符串。仅是路径名序列中的last name
。如果路径名序列为空,则返回空字符串。
System.out.println(imageFile.getPath()); // /..\index.txt
getAbsolutePath
返回文件的绝对路径。绝对路径由文件系统的根目录开始。在Android中,只有一个根:"/"
绝对路径的一个常见用法是将路径作为命令行参数传递给进程,以消除相对路径隐含的要求,即子路径必须与其父路径具有相同的工作目录。
getCanonicalPath
返回此抽象路径名的规范路径名字符串。
规范路径名既绝对又唯一。规范形式的精确定义依赖于系统。此方法首先在必要时将此路径名转换为绝对形式,就像调用getAbsolutePath()
方法一样,然后以依赖于系统的方式将其映射到其唯一形式。这通常涉及从路径名中删除冗余名称(如“.”
和“..”
)解析符号链接(在UNIX平台上),以及将驱动器号转换为标准大小写(在Microsoft Windows平台上)。
表示现有文件或目录的每个路径名都有一个唯一的规范形式。每个表示不存在的文件或目录的路径名也有一个唯一的规范形式。不存在的文件或目录的路径名的规范形式可能与创建文件或目录后相同路径名的规范形式不同。类似地,现有文件或目录的路径名的规范形式可能与删除该文件或目录后相同路径名的规范形式不同。