在我的博客:JavaIO之File类 中介绍了关于File类,该类用于处理文件本身(如:创建文件、删除文件等),并不能对文件的内容进行处理。如果要处理文件的内容,必须要通过流的操作来完成,在java.io包中流含有字节流和字符流。而字节流或字符流中又分为输入流和输出流。下面详细介绍字节流和字符流。
1. 字节流
字节流是由字节组成的,主要处理二进制数据,它的操作是原生的。字节流的操作步骤主要分为4步(以处理文件为例):
(1)根据文件路径创建File类对象
(2)根据字节流的子类实例化父类对象
(3)进行数据的读取、写入等操作
(4)关闭流(close())
1.1 字节输出流:OutputStream
如果想要通过程序进行内容的输出操作,则可以使用java.io.OutputStream类。下面观察OutputStream类的部分源码:
public abstract class OutputStream implements Closeable, Flushable
(1)由于OutputStream类是一个抽象方法,所以要想实例化其对象,必须要使用其子类。如果要对文件进行处理,可以使用FileOutputStream类。FileOutputStream类中的某两个构造方法:
①接收File类(覆盖文件内容):
public FileOutputStream(File file) throws FileNotFoundException
②接收File类(追加文件内容):
public FileOutputStream(File file, boolean append)
(2)OutputStream类实现了Closeable和Flushable接口,这两个接口中的只含有如下方法:
Closeable接口中的close()方法:
public void close() throws IOException;
Flushable接口中的flush()方法:
void flush() throws IOException;
(3)在OutputStream类中除了覆写了以上两个方法外,还有其他方法:
①将给定的字节数组内容全部输出:
public void write(byte b[]) throws IOException
②将部分字节数组内容输出:
public void write(byte b[], int off, int len) throws IOException
③输出单个字节:
public abstract void write(int b) throws IOException;
1.2 实现将字符串输出到文件中:
package www.bit.java.test;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
public class Test1 {
public static void main(String[] args) throws Exception {
//实现将字符串输出到文件中
//1.创建File类的实例化对象
File file=new File("C:"+File.separator+"Users"+File.separator+
"Administrator"+File.separator+"Desktop"+File.separator+"File.txt");
if(!file.getParentFile().exists()) {
file.getParentFile().mkdirs();
}
//2.由于OutputStream类是一个抽象类,需要通过其子类实例化对象
OutputStream output=new FileOutputStream(file);
//3.进行数据的输出操作,即将数据写入到文件中
String string="将数据输出到文件中";
//由于write()方法接收的是字节数组,故将字符串转为字节数组再写入
output.write(string.getBytes());
//4.关闭流
output.close();
}
}
需要注意的是:文件输出流FileOutputStream类默认为覆盖文件原有内容的操作,若不想覆盖原有内容,只是将内容进行追加的话,实例化OutputStream类对象不再使用FileOutputStream(File file)而是使用FileOutputStream(File file,boolean append),并且将append值置为false表示覆盖内容,将append值置为true表示追加内容。
1.3 自动关闭流与手动关闭流
在之前的操作中,我们使用Closeable接口中的close()方法手动关闭流,而在JDK1.7以后追加了AutoCloseable接口,这个接口的主要目的是自动进行流的关闭处理,但是存在一个麻烦的步骤就是它必须结合try...catch。
修改之前的将字符串输出到文件中的操作,使用AutoCloaseable接口实现自动关闭流操作。下面观察AutoCloseable接口的使用:
package www.bit.java.test;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
public class Test1 {
public static void main(String[] args) throws Exception {
File file=new File("C:"+File.separator+"Users"+File.separator+
"Administrator"+File.separator+"Desktop"+File.separator+"File.txt");
if(!file.getParentFile().exists()) {
file.getParentFile().mkdirs();
}
//使用AutoCloseable接口实现自动关闭流,但流的实例化对象必须定义在try块中
try(OutputStream output=new FileOutputStream(file,true)){
String string="将数据输出到文件中";
output.write(string.getBytes());
}catch (Exception e) {
e.printStackTrace();
}
}
}
1.4 字节输入流:InputStream
利用OutputStream类实现了程序内容输出到文件的操作,下面使用InputStream类实现在程序中读取文件内容的操作。下面关于InputStream类的部分源码如下:
public abstract class InputStream implements Closeable
观察发现InputStream类实现了Closeable接口,在InputStream类中含有如下方法:
(1)读取数据到字节数组中,返回数据的读取个数。
public int read(byte b[]) throws IOException
需要注意的是其返回值的大小:
①如果开辟的字节数组的大小大于读取的数据的大小,则返回读取的数据的大小
②如果开辟的字节数组的大小小于读取的数据的大小,则返回字节数组的大小
③如果流中没有数据但还在读取时,返回-1
(2)读取部分数据到字节数组中,每次只读取数组的部分内容,返回数据的读取个数。
public int read(byte b[], int off, int len) throws IOException
该方法与read(byte b[])类似,返回的个数为:
①如果读取到数组指定长度的内容,则返回数组指定长度len
②如果没有读取到数组指定长度的内容,则返回读取的个数
③如果流中没有数据但还在读取时,返回-1
(3)读取单个字节,每次读取一个字节的内容,直到没有数据了返回-1
public abstract int read() throws IOException;
1.5 实现文件内容到程序中的读取操作
同OutputStream类的使用一样,由于InputStream类是一个抽象类,如果要对其实例化对象,需要使用其子类。若处理的是文件,则使用FileInputStream类进行实例化对象。
package www.bit.java.test;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
public class Test1 {
public static void main(String[] args) throws Exception {
//1.实例化File类对象
File file=new File("C:"+File.separator+"Users"+File.separator+
"Administrator"+File.separator+"Desktop"+File.separator+"File.txt");
//对文件进行读取操作,必须保证该文件存在
if(file.exists()) {
//2.由于InputStream类是抽象类,故用其子类FileInputStream类对其实例化对象
InputStream input =new FileInputStream(file);
//3.对文件进行读取操作
byte[] data=new byte[1024];
int len=input.read(data);
String string=new String(data,0,len);
System.out.println("从文件中读取的内容为:"+string);
//4.关闭流
input.close();
}
}
}
运行结果为:
从文件中读取的内容为:将数据输出到文件中
2. 字符流
字符流是由字符组成的,主要处理中文数据,它的操作是是经过处理的。字符流的操作步骤与字节流的操作步骤相同,也分为4步(以处理文件为例):
(1)根据文件路径创建File类对象
(2)根据字符流的子类实例化父类对象
(3)进行数据的读取、写入等操作
(4)关闭流(close())
2.1 字符输出流:Writer
关于Writer类的部分源代码如下:
public abstract class Writer implements Appendable, Closeable, Flushable
(1)与OutputStream类相比,它多实现了一个Appendable接口。在Writer类中也提供了write()方法,但需要注意的是Writer类中提供了一个直接接收字符串的方法:
public void write(String str) throws IOException
(2)观察Writer类的定义可以看出,该类是抽象类,要想实例化Writer类对象,就需要其子类去实例化对象。如果要操作文件的话,需要FileWriter子类去实例化对象。
2.2 通过Writer类实现程序到文件的输出操作
package www.bit.java.test;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.InputStream;
import java.io.Writer;
public class Test1 {
public static void main(String[] args) throws Exception {
//1.实例化File类对象
File file=new File("C:"+File.separator+"Users"+File.separator+
"Administrator"+File.separator+"Desktop"+File.separator+"File.txt");
//必须保证文件的父目录都存在
if(!file.getParentFile().exists()) {
file.getParentFile().mkdirs();
}
//2.由于Writer类是抽象类,故用其子类FileWriter类对其实例化对象
Writer writer =new FileWriter(file);
//3.对文件进行操作
String string="将程序内容输出到文件中";
writer.write(string);
//4.关闭流
writer.close();
}
}
需要注意Writer类与OutputStream类的一点区别:
(1)Writer类会把数据先放在缓冲区,如果操作结束没有关闭流,则不会将数据写入到目标终端。此时,要想把数据写入到目标终端,可以有两个方法:①调用close()从而关闭流;②调用flush()从而强制清空缓冲区。
(2)OutputStream类即使没有关闭流也会将内容写入到目标终端。
2.3 字符输入流:Reader
先来观察Reader类的部分源代码:
public abstract class Reader implements Readable, Closeable
(1)Reader类依然是一个抽象类,要想实例化其对象就需要其子类实例化对象。如果要操作的是文件,则使用FileReader子类实例化对象。
(2)Writer类中提供了一个可以直接向目标终端写入字符串的方法,但Reader类没有该类型方法,故也只能通过字符数组进行操作。
2.4 通过Reader类实现文件到程序的读取操作
package www.bit.java.test;
import java.io.File;
import java.io.FileReader;
import java.io.Reader;
public class Test1 {
public static void main(String[] args) throws Exception {
//1.实例化File类对象
File file=new File("C:"+File.separator+"Users"+File.separator+
"Administrator"+File.separator+"Desktop"+File.separator+"File.txt");
//必须保证文件存在才可以进行读取操作
if(file.exists()) {
//2.由于Reader类是抽象类,故用其子类FileReader类对其实例化对象
Reader reader =new FileReader(file);
//3.对文件进行读取操作
char[] data=new char[1024];
int len=reader.read(data);
String string=new String(data,0,len);
System.out.println("从文件中读取的内容为:"+string);
//4.关闭流
reader.close();
}
}
}
运行结果为:
从文件中读取的内容为:将程序内容输出到文件中
总结字节流和字符流的使用范围:
进行IO处理时,如果处理的是图片、音乐、文字都可以使用字节流;只有在处理中文的时候才使用字符流。