Java中的流,可以从不同的角度进行分类。
按照数据流的方向不同可以分为:输入流和输出流。
按照处理数据单位不同可以分为:字节流和字符流。
按照功能不同可以分为:节点流和处理流。
字节流:一次读入或读出是8位二进制(也就是一个字节)
字符流:一次读入或读出是16位二进制(char在Java中是16位的,因为Java用的是Unicode)
Stream是字节流,Reader,Writer是字符流。
节点流:直接与数据源相连,读入或读出。
处理流:与节点流一块使用,在节点流或处理流的基础上,再套接一层,套接在其他流上的就是处理流。处理流必定有以流为参数的构造函数,例如:
DataInputStream(InputStream in)
//使用指定的底层 InputStream 创建一个 DataInputStream。
节点流只提供了最基础的读写功能,而处理流则提供了更为丰富的功能,例如读整行,带缓冲区读写等
四个最基本的流
官方提供的所有IO流都继承自以下四个抽象类:
InputStream 定义了3个read方法
int read();
int read(byte[]);
int read(byte[],int off,int len);
read( ) : 从输入流中读取数据的下一个字节。返回 0 到 255 范围内的 int 字节值。如果因为已经到达流末尾而没有可用的字节,则返回值 -1。
read(byte[]) : 其实就是read(b, 0, b.length) ,所以等同于第三个
read(byte[],int off,int len) : 将输入流中最多 len 个数据字节读入 byte 数组。尝试读取 len 个字节,但读取的字节也可能小于该值。以整数形式返回实际读取的字节数。类 InputStream 的 read(b, off, len) 方法重复调用方法 read()。建议子类提供此方法更为有效的实现。
因此,这里的第二第三个方法并没有真正实现缓冲,缓冲与否要看子类的具体实现
OutputStream 定义了3个write方法另外有一个重要的flush方法
//向输出流写入一个字节。要写入的字节是参数 b 的八个低位。b 的 24 个高位将被忽略。
void write(int b);
void write(byte[]);
void write(byte[],int off,int len);
void flush()
三个write与read相对应,不再叙述
flush( ) : java在使用输出流时,都会有一个缓冲区,按一种它认为比较高效的方法来发数据:把要发的数据先放到缓冲区,缓冲区放满以后再一次性发过去,而不是分开一次一次地发.而flush()表示强制将缓冲区中的数据发送出去,不必等到缓冲区满.所以在流close之前应先执行flush
Reader流
int read();
int read(char[]);
int read(char[],int off,int len);
和InputStream相比,除了参数中byte变为char,每次的读取单位由一个字节变为一个字符之外,其余相同
Writer流
//向输出流写入一个字节。要写入的字节是参数 b 的 16 个低位。b 的 16 个高位将被忽略。
void write(int b);
void write(char[]);
void write(char[],int off,int len);
void write(String);
void write(String s,int off,int len);
void flush()
与OutputStream同理,只是输出单位从字节变为字符。另外,增加了两个输出String的方法,究其原因是因为String类有toCharArray()方法。
具体的IO流
文件流 :FileInputStream,FileReader,File……
FileReader 用于读取字符流,是用来读取字符文件的便捷类,因为字符采用Unicode,因此可以读所有语言的文本,前提是文本编码格式为Unicode(windows默认为ANSI)。要读取原始字节流,例如图像,请考虑使用 FileInputStream。 Out和Writer同理。
缓冲流:BufferedInputStream,BufferReader,Buffe……
buffer流为处理流,为其他流提供缓存以及mark和reset等功能,需要指出的是,BufferReader中有readline方法,可以一次读取一行。BufferWriter中有newline方法,可以写入一个换行
转换流:InputStreamReaderOutputStreamFileWriter
将字节流转换为字符流,并能指定转换时使用的解码方式。在字符流与字节流之间架起了一座桥梁,使原本毫无关联的两种流操作能够进行转化,提高了程序的灵活性。
//指定解码方式示例
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("F:\\test.txt");
InputStreamReader isr = new InputStreamReader(fis,"gbk");/*关于windows默认的ANSI编码,
不同地区ANSI编码是不一样的, 简体中文对应的是 GBK*/
BufferedReader br = new BufferedReader(isr);
System.out.println(br.readLine());
}
数据流:DataInputStream,DataOutputStream
输入输出基本类型,例如writeInt,readChar,以及一个很有用的方法,readUTF与writeUTF
字节数组流:ByteArrayOutputStream,ByteArrayInputStream
Out : 数据被写入一个自动生成的 byte 数组。缓冲区会随着数据的不断写入而自动增长。可使用 toByteArray() 和 toString() 获取数据。
In :能将一个字节数组当成输入,然后根据需要套接处理流,执行各种操作
打印流(标准输出流):PrintWriter,PrintStream
以标准打印的方法将内容打印入指定的设备
public static void main(String[] args) throws IOException {
FileOutputStream fos = new FileOutputStream("F:\\test.txt");
PrintStream ps = new PrintStream(fos);//setOut的参数是printStream类型的,因此把file套接成print
System.setOut(ps);//指定输出到文件test.txt
int a = 5;
double d = 76.78;
/*因为已经setOut了,所以以下全部打印到文件里面*/
System.out.println(a);//运用各式各样的标准输出方式
System.out.println(d);
System.out.printf("int = %d double = %f",a,d);
}
运行之后,文件test.txt里面内容:
Scanner(文本扫描器)
Scanner并不是IO流,但配合IO有实用价值,因此也在此写下。Scanner类提供了丰富的处理文本的方法,例如正则,nextInt(),nextDouble(),我们可以通过System.setIn()设定其指定的读取设备
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("F:\\test.txt");
System.setIn(fis);
Scanner sc = new Scanner(System.in);
String s = sc.next();//会从输入流读入一个字符串,以空格或换行符为标志
System.out.println(s);
int a = sc.nextInt();
System.out.println(a);
}
对象流:ObjectInputStream,ObjectOutputStream
能将对象序列化与反序列化的流(Serialization(序列化)是一种将对象以一连串的字节描述的过程;反序列化deserialization是一种将这些字节重建成一个对象的过程。)。被序列化的对象需要实现serializable接口,该接口标记型接口,无需写具体实现
public class Welcome {
public static void main(String[] args) throws IOException, ClassNotFoundException {
T obj = new T();
FileOutputStream fos = new FileOutputStream("F:\\ob.dat");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(obj);
oos.flush();
oos.close();
FileInputStream fis = new FileInputStream("F:\\ob.dat");
ObjectInputStream ois = new ObjectInputStream(fis);
T another = (T) ois.readObject();
System.out.println(another.a + " " + another.d + " " + another.s);
}
}
class T implements Serializable{
int a = 4;
double d = 7.89;
String s = "咸橙";
}