在Java中,一个可以读取字节序列的对象被称为输入流,一个可以写入字节序列的对象被称为输出流。在抽象类InputStream和OutputStream中对它们进行了说明。
读写字节
InputStream类有一个抽象的方法:
abstract int read()
该方法将读取一个字节,并将其返回。如果已经读到了输入源的末尾,将返回-1。具体的输入流类的设计者覆盖这个方法以提供具体的功能实现。例如,System.in是一个预定义的InputStream的子类的对象,使用它可以从键盘读取信息。
同样地,OutputStream类定义了这个抽象方法:
abstract void write(int b)
将一个字节写到指定的输出位置。
这里的read方法和write方法都是阻塞I/O。
available方法可以检查目前可以读取的字节数。也就是说,下面这样的代码不可能永远被阻塞:
int bytesAvailable = in.available(); if(bytesAvailable > 0) { byte[] data = new byte[bytesAvailable]; in.read(data); }
当完对一个流的读取或者写入后,就应该调用close方法将它关闭,这样可以释放流所占用的操作系统资源。关闭一个输出流也可以冲洗(flush)输出流占用的缓存区,即临时存储在缓冲区中等待形成较大的数据包后再发送的那些字符,此时将他们发送出去。
流过滤器的分层
FileInputStream和FileOutputStream能够把输入和输出流与磁盘文件关联起来。例如:
FileInputStream fin = new FileInputStream("employee.data");
也可以使用一个File对象
File f = new File("employee.dat");
FileInputStream fin = new FileInputStream(f);
因为所有在java.io中的类都是将相对路径名解释为起始于用户的当前工作目录,所以应该清楚当前的目录。可以通过调用System.getProperty("user.dir")来获得。
与抽象类的InputStream和OutputStream类似,这些类只在字节层次上支持读写。这意味着,只能从fin对象中读取字节和字节数组。
byte b = (byte)fin.read();
一些流(例如FileInputStream以及URL类中利用openStream方法来返回的输入流)可以从文件以及其他地方接收字节。另一些流(例如DataInputStream和PrintWiter)可以将字节组合成更加有用的数据类型。Java程序员采用将一个已经存在的流传递给另一个流的构造器方法,将这两种流结合起来,结合后的流被称为过滤流。例如:
FileInputStream fin = new FileInputStream("employee.dat");
DataInputStream din = new DataInputStream(fin);
double s = din.readDouble();
非常重要的一点是:利用上面的代码建立的数据输入流并没有与一个新的磁盘文件对应。新创建的流依然通过访问与文件输入流相联系的文件获取数据。但是,现在可以使用一种功能更多的接口了。
java.io.BufferedInputStream 1.0
BufferedInputStream(InputStream in)
新建一个默认大小的缓冲流。缓冲的输入流从一个流中读取字节,而不会每次都引起对设备的访问。当缓冲区空时,一个新的数据块会被读入缓冲区。
BufferedInputStream(InputStream in, int n)
根据用户自定义缓冲区大小,新建一个缓冲流。
java.io.BufferedOutputStream 1.0
BufferedOutputStream(OutputStream out)
新建一个默认缓冲大小的缓冲流。缓冲输出流收集写入的字符以免每次都引起对设备的访问。当缓存区满或者流被冲洗时,数据被写入设备。
BufferedOutputStream(OutputStream out, int n)
根据用户自定义的缓冲区大小,新建一个缓冲流。
java.io.PushbackInputStream 1.0
PushbackInputStream (InputStream in)
构造一个预查看一个字节的流。
PushbackInputStream (InputStream in, int size)
使用指定大小的pushback缓冲区构造一个流。
void unread(int b)
返回一个字节,下次调用读取时仍会再次得到该字节。一次只能返回一个字节。参数b:再次被读取的字节。
随机存取文件流
RandomAccessFile流类能够在文件的任何位置查找或者写入数据。他同时实现了DataInput和DataOutPut接口。磁盘文件可以随机存取,但是来自网络的数据流就不行了。随机存取文件提供了一个文件指针。文件指针总是指向下一条要进行读写操作记录的位置。Seek方法指定文件指针的位置,getFilePointer方法返回文件指针的当前位置。
java.io.RandomAccessFile 1.0
RandomAccessFile(String file, String mode)
RandomAccessFile(File file, String mode)
参数:file 将被打开的文件
mode "r":只读,"rw":读/写, "rws":同步读写, "rwd":同步读写
long getFilePointer()
返回文件指针的当前位置。
void seek(long pos)
将文件指针的位置设定为从文件开始的pos字节处。
long length()
返回文件的长度(以字节记)
java.io.DataInput 1.0 //DataInput是一个接口哪个类实现了这个接口,就是定义了接口中的方法。
boolean readBoolean()
byte readByte()
char readChar()
double readDouble()
float readFloat()
void readFully(byte[] b)//将所有字节读入字节数组b中,阻塞直到全部字节被读取为止。
void readFully(byte[] b, int off, int len)// off:数据开始位置的偏移量,len:读取字节的最大数
int readInt()
String readLine()//读取一行,直到 , , 或者EOF。返回字符串
long readLong()
short readShort()
String readUTF()//使用"modified-UTF-8"格式读取一个字符组成的字符串
int skipBytes(int n)//跳过n个字节
java.io.DataOutput 1.0
与DataInput接口对应。例如,有boolean readBoolean(),就有void writeBoolean(boolean b)。
注意,与readFully相对应的是void writeChars(String s),将字符串s写入。
这里插一条接口的笔记:接口类型可以作为形参类型,而所有实现了该接口的类都可以作为实参类型。例如:
class Employee
{
read(DataInput in){...}
write(DataOutput out){...}
}
RandomAccessFile类实现了DataInput 和DataOutput 接口,因此read方法和write方法的实参可以是RandomAccessFile类的对象。