java的流中:以二进制读取的流主要有:
1.InputStream/OutputStream: 这是基类,它们是抽象类。
2.FileInputStream/FileOutputStream: 输入源和输出目标是文件的流。
3.ByteArrayInputStream/ByteArrayOutputStream: 输入源和输出目标是字节数组的流。
4.DataInputStream/DataOutputStream: 装饰类,按基本类型和字符串而非只是字节读写流。
5.BufferedInputStream/BufferedOutputStream: 装饰类,对输入输出流提供缓冲功能。
InputStream – 抽象类
单个字节读取:
public abstract int read() throws IOException;
read从流中读取下一个字节,返回类型为int,但取值在0到255之间,当读到流结尾的时候,返回值为-1,如果流中没有数据,read方法会阻塞直到数据到来、流关闭、或异常出现,异常出现时,read方法抛出异常,类型为IOException,这是一个受检异常,调用者必须进行处理。read是一个抽象方法,具体子类必须实现,FileInputStream会调用本地方法,所谓本地方法,一般不是用Java写的,大多使用C语言实现,具体实现往往与虚拟机和操作系统有关。
批量读取:
public int read(byte b[]) throws IOException
读入的字节放入参数数组b中,第一个字节存入b[0],第二个存入b[1],以此类推,一次最多读入的字节个数为数组b的长度,但实际读入的个数可能小于数组长度,返回值为实际读入的字节个数。如果刚开始读取时已到流结尾,则返回-1,否则,只要数组长度大于0,该方法都会尽力至少读取一个字节,如果流中一个字节都没有,它会阻塞,异常出现时也是抛出IOException。该方法不是抽象方法,InputStream有一个默认实现,主要就是循环调用读一个字节的read方法,但子类如FileInputStream往往会提供更为高效的实现。
读入的第一个字节放入b[off],最多读取len个字节
public int read(byte b[], int off, int len) throws IOException
read(byte[] b)内部就是调用了该方法。
public int read(byte b[]) throws IOException {
return read(b, 0, b.length);
}
流读取结束后,应该关闭,以释放相关资源,关闭方法为:
public void close() throws IOException
OutputStream --抽象类
基本方法:
public abstract void write(int b) throws IOException;
批量写入:
public void write(byte b[]) throws IOException
public void write(byte b[], int off, int len) throws IOException
在第二个方法中,第一个写入的字节是b[off],写入个数为len,最后一个是b[off+len-1],第一个方法等同于调用:write(b, 0, b.length);。OutputStream的默认实现是循环调用单字节的write方法,子类往往有更为高效的实现,FileOutpuStream会调用对应的批量写本地方法。
public void flush() throws IOException
public void close() throws IOException
flush将缓冲而未实际写的数据进行实际写入,比如,在BufferedOutputStream中,调用flush会将其缓冲区的内容写到其装饰的流中,并调用该流的flush方法。基类OutputStream没有缓冲,flush代码为空。
需要说明的是文件输出流FileOutputStream,你可能会认为,调用flush会强制确保数据保存到硬盘上,但实际上不是这样,FileOutputStream没有缓冲,没有重写flush,调用flush没有任何效果,数据只是传递给了操作系统,但操作系统什么时候保存到硬盘上,这是不一定的。要确保数据保存到了硬盘上,可以调用FileOutputStream中的特有方法。
close一般会首先调用flush,然后再释放流占用的系统资源。同InputStream一样,close一般应该放在finally语句内。
DataInputStream/DataOutputStream
void writeBoolean(boolean v) throws IOException;
void writeInt(int v) throws IOException;
void writeDouble(double v) throws IOException;
void writeUTF(String s) throws IOException;
在使用这些写入写出的方式时,需要注意写入跟写出的调用方法的顺序需要相等
output.writeInt(students.size());
for(Student s : students){
output.writeUTF(s.getName());
output.writeInt(s.getAge());
output.writeDouble(s.getScore());
}
int size = input.readInt();
List<Student> students = new ArrayList<Student>(size);
for(int i=0; i<size; i++){
Student s = new Student();
s.setName(input.readUTF());
s.setAge(input.readInt());
s.setScore(input.readDouble());
students.add(s);
}
像这两段代码,如果写出跟写入的顺序不一样,会爆EOFException,表示意外的读取到了文件的最后,如果后面还在调用read方法但又没有数据的时候就会报错。
BufferedInputStream/BufferedOutputStream
具有缓冲功能的字节流。读取时,先从这个缓冲区读取,缓冲区读取完了后在调用安装的流读,提高性能,它的flush方法会将缓冲区的内容写到包装的流中。