java中,IO流是非常重要的一部分,它是用于设备设备之间的数据传输。
IO流的分类可以分两种,一种按照流的方向分:分为输入流和输出流,一种是按照数据类型分:分为字节流和字符流。
这里主要讲讲这IO流以及它们的子类。
1、字节流
字节输入流和字节输出流它们的子类分别是InputStream和OutputStream,它们都是抽象类,需要通过子类来实例化。
InputStream----->FileInputStream 文件基本输入流,字节输入流的子类。其构造方式为:
FileInputStream fis = new FileInputStream("a.txt") ;是可以对文件进行直接操作的,表示读取该文件。
在读取文件时,可以单个字节读入,也可以一次读入一个字节数组,字节数组的大小可以自己指定,比如定义的是
5个字节大小的数组,那么就可以一次性读入五个字节,在java中,我们一般定义字节数组的大小为1024个。首先讲一
下单个字节读入的方法:
1)//public intread()方法
int by = 0 ;//定义一个字节用于接收
while((by=fis.read())!=-1){
System.out.print((char)by);
}
在这段代码里面,by是返回的一个 0
到 255
范围内的int
字节值,如果因为已经到达流末尾而没有字节可用,则返回-1
。
所以将-1用做读取完毕的标志,这里需要注意的是,读取出来的是字节,所以想要将其作为字符打印出来观察,需要强制类型转换。
2)public intread(byte[] b):方法一次读取一个字节数组
byte[] bys = new byte[1024] ;
int len = 0 ; //读取字节数的实际长度
while((len=fis.read(bys))!=-1){
System.out.println(new String(bys,0,len));
首先定义一个长度为1024的字节数组,此字节数组用于接收每次读取的字节数,注意这个方法返回的是每次读取的字节的实际大小,比如你每次读取1024个字节,但是其中只有5个是实际有效的,那么返回的值就是5,这里需要和上面的单个字节读取区分开来,上面定义的BY是即作为结束的标志,同时也是每次读取出来的实际字节值,将它强制类型转换之后就可输出。但是在这里,len作为读取结束的标志使用,而字节数组存储的是实际读取的字节值,要将它输出可以调用String中的构造方法,传入一个字节数组,返回一个
OutpuStream---->FileOutoutStream 文件基本输出流,字节输出流的子类。其构造方式为:
FileOutputStream fis = new FileOutputStream("a.txt") ;可以直接对文件进行操作,表示向文件写入数据。
其write方法对应上面的read方法,一次写入一个字节或者一个字节数组,另外输出流中的flush方法是经常需要用到的,因为它是刷新每次数据,强制将所有已缓冲的输出字节写入该流中,比如在加载图片的时候回出现加载一半的情况,使用flush方法就是将其为写入的部分强制写入。
这两个方法的不同处除了在每次读的字节数上,还体现在其读写速度上,当使用字节数组来读取时,其速度比起单个字节的读取快了很多,差不多是其的1000倍。
字节流中除了基本输入输出流之外,还有一种缓冲区字节输入输出流BufferedInputStream和BufferedOutputStream。其构造方法分别为 BufferedInputStream bis = new BufferedInputStream(new FileInputStream("bis.txt")) ;
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("bos.txt"));
可以看出来,缓冲区字节输入输出流,其最后还是依靠基本输入输出流来对文件进行操作的。这是因为缓冲流只是一个缓冲区,
而对IO流进行实现数据的传输实际是通过底层基本输入输出流实现的,自己本身是不能直接对文件进行操作,但是缓冲流可以提高读写速度。
2、字符流
字符流Writer和Reader,是字符输入输出流的父类,和字节输入输出流一样也是抽象类,它们是对字符进行直接操作的。
它们的子类是:
Writer--->OutputStreamWriter ---->FileWriter
Reader--->InputStreamReader---->FileReader
其中OutputStreamWriter和InputStreamReader叫做字符转换流,同样这里也是通过给他的构造方式来介绍它的作用
输出: OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("osw.txt"));
输入: InputStreamReader isr = new InputStreamReader(new FileInputStream("osw.txt"));
从它们的构造方式可以看出,它们也是通过底层基本输入输出字节流来实现对文件的操作,通过基本字节流将其转换为字符流进行输入输出。
同样,字符流的读取也是分为一次性读取一个字符或者一个字符数组,下面分别给出两种方式的代码。
1)一次读取一个字符:
int ch = 0 ;
while((ch=isr.read())!=-1){
System.out.print((char)ch);
}
每次返回的是该字符的默认GBK编码,最后转换为字符输出。
2)一次读取一个字符数组:
char[] chs = new char[1024] ;
int len = 0;
while((len=isr.read(chs))!=-1){
System.out.println(new String(chs, 0, len));
}
一次读取一个字符数组,这个返回的值,我的理解是此次读取的实际字符数以及加上“\r\n”两个结束符,如果将此次读取的字符数转成字节数组用于查看,可以看出,
他有len-1个字节编码,那是因为最后的那个编码是光标的位置,下次从此处开始写数据。比如;读取的文件里面是中国两个字符,用下面这段代码去测试
char[] chs = new char[1024] ;
int len = 0;
while((len=isr.read(chs))!=-1){
System.out.print(len);
System.out.println(new String(chs, 0, len-2));
byte[] by=new String(chs, 0, len).getBytes();
System.out.println(Arrays.toString(by));
}
可以发现,结果是4中国
[-42, -48, -71, -6, 13, 10],后面的13,10这两个编码就是光标。4是此次读取的实际字符数,“中国”则是实际内容。
而如果用上面的代码进行字符输入输出的构造,太过麻烦,所以java中就提供了一种便捷类用于构造字符流,那就是FileWriter和FileReader,它们的构造方式是:
FileReader fr = new FileReader("a.txt") ;
FileWriter fw = new FileWriter("b.txt") ;
是可以直接对文件进行操作的,比起上面的方法,代码看起来简洁了很多。他的读写方式和上面一样,就不再多说了。
2、和字节流一样,为了提高文件的读写速度,提出了字符缓冲流,BufferedWriter和BufferedReader。
构造方式分别为:BufferedWriter bw = new BufferedWriter(new FileWriter("bw.txt")) ;
BufferedReader br = new BufferedReader(new FileReader("bw.txt")) ;
它们也是不能直接对文件进行操作的,需要将字符流传入,然后再进行读写操作。
在字符缓冲流中需要注意两个特殊功能,
关于字符缓冲输入流的特有功能:
BufferedWriter:
public void newLine():写入一个换行符号
BufferReader:
public String readLine():一次读取一行
用readLine()进行读取文件,一次可以读取一行,而他的循环结束条件就不在是-1了,而是null,
String line = null ;
while((line=br.readLine())!=null){
System.out.println(line);
}
用 newLine()可以当做一个换行符使用。
这些就是IO流中的基本分类,下次再讲讲IO流中的其他流