在Java中File类对象,可以用来操作文件,但是不能处理文件内容
为了处理文件内容,进行 I/O 操作,必须使用流的操作模式来完成
I/O流体系结构图:
I/0流分类:
1)根据处理的数据类型分为:字节流和字符流
2)根据处理的数据流向分为:输入流和输出流
字节流与字符流的区别:
字节流和字符流操作的本质区别只有一个:字节流是原生的操作,而字符流是经过处理后的操作。
在进行网络数据传输、磁盘数据保存所保存所支持的数据类型只有:字节
而所有磁盘中的数据必须先读取到内存后才能进行操作,而内存中会帮助我们把字节变为字符。
字节流和字符流的具体区别总结如下:
- 字节流处理二进制数据,适合处理一切数据类型(对中文支持不好);字符流处理字符数据,适合处理中文。
- 字节流在操作时不会用到缓冲区,是文件本身直接操作的,而字符流在操作时使用了缓冲区,通过缓冲区来操作文件。
那么根据上面的分类,就可以得到以下四种基本I/O流
- 字节输入流 OutputStream
- 字节输出流 InputStream
- 字符输入流 Reader
- 字符输出流 Writer
接下来,让我们来依次了解这四种基本I/O流的使用方法
一、字节输入流 OutputStream
如果想通过程序输出内容到文件,则可以使用java.io.OutputStream
OutputStream类主要方法:
1. 将给定的字节数组内容全部输出:public void write(byte b[]) throws IOException
2. 将部分字节数组内容输出:public void write(byte b[], int off, int len) throws IOException
3. 输出单个字节:public abstract void write(int b) throws IOException
范例:实现文件的内容输出
import java.io.*;
public class Test1 {
public static void main(String[] args) {
File file =new File("C:"+File.separator+"Users"+File.separator+"10320"+
File.separator+"ideaProjects"+File.separator+"file.txt");
if(!file.getParentFile().exists()){//判断父目录存在
file.getParentFile().mkdirs();//创建多级父目录
}
// OutputStream是一个抽象类,所以需要通过子类进行实例化,此时只能操作File类
try {
OutputStream output=new FileOutputStream(file);
//此构造方法会不断覆盖内容
//如果变为以下构造方法,即可实现追加内容
// OutputStream output=new FileOutputStream(file,true);
String message="hello word";
output.write(message.getBytes());//将内容变为字节数组
output.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
注意:由于OutputStream是一个抽象类,不能实例化对象,所以要想为父类实例化,就必须要使用子类(子类实现抽象父类的方法,但是自身并不是抽象类,所以可以实例化对象)。由于方法名称都由父类声明好了,所以我们在此处只需要关系子类的构造方法。如果要进行文件的操作,可以使用FileOutputStream类来处理。
FileOutputStream类的构造方法如下:
1. 接收File类(覆盖):public FileOutputStream(File file) throws FileNotFoundException
2. 接收File类(追加):public FileOutputStream(File file, boolean append)
二、字节输出流 InputStream
使用InputStream类,可以在程序中读取文件内容
InputStream类主要方法:
1. public int read(byte b[]) throws IOException
读取数据到字节数组中,返回数据的读取个数。如果此时开辟的字节数组大小大于读取的数据大小,则返
回的就是读取个数;如果要读取的数据大于数组的内容,那么这个时候返回的就是数组长度;如果没有
数据了还在读,则返回-12. public int read(byte b[], int off,int len) throws IOException
读取部分数据到字节数组中,每次只读取传递数组的部分内容,如果读取满了则返回长度(len),如果没有
读取满则返回读取的数据个数,如果读取到最后没有数据了返回-13. public abstract int read() throwsIOException
读取单个字节,每次读取一个字节的内容,直到没有数据了返回-1
范例:实现文件信息的读取
public class Test1 {
public static void main(String[] args) {
//定义文件路径
File file = new File("C:" + File.separator + "Users" + File.separator + "10320" + File.separator + "ideaProjects" + File.separator + "file.txt");
if(file.exists()){
try {
// InputStream类是抽象类,必须利用其子类FileInputStream实例化对象,此时只能处理File类
InputStream input=new FileInputStream(file);//构造方法
byte[] data =new byte[1024];//每次可以读取的最大数量
int len=input.read(data);//此时的数据读取到了数组当中
String result = new String(data,0,len) ; // 将字节数组转为String
System.out.println("读取内容【"+result+"】") ;
input.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
三、字符输入流 Reader
Reader是字符输入流的处理类,可以通过程序实现读取文件内容
Reader类主要方法:
- public abstract int read()throws IOException 读取单个字符
- public int read(char[] c) throws IOException 读取数据到字符数组
- public int read(char[] c,int off,int len) throws IOException 读取部分数据到字符数组
在Reader类中没有方法可以直接读取字符串类型,这个时候只能通过字符数组进行读取操作
范例:通过Reader类读取文件内容
public class Test1 {
public static void main(String[] args) {
//定义文件路径
File file = new File("C:" + File.separator + "Users" + File.separator
+ "10320" + File.separator + "ideaProjects" + File.separator + "file.txt");
if(file.exists()){
try {
// Reader类是抽象类,必须利用其子类FileReader实例化对象,此时只能处理File类
Reader in = new FileReader(file) ;
char[] data = new char[1024] ;
int len = in.read(data) ; // 将数据读取到字符数组中
String result = new String(data, 0, len) ;
System.out.println("读取内容【"+result+"】") ;
in.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
四、字符输出流 Writer
字符流适合于处理中文数据,Writer是字符输出流的处理类,可以通过程序实现向文件写入内容
Writer类主要方法:
- public void write(String str) throws IOException 将str字符串直接输出到输出流中
- public void write(String str,int off,int len) 将str字符串里从off位置开始长度为len的字符输出到输出流中
范例:通过Writer类实现输出
public class Test1 {
public static void main(String[] args) {
//定义文件路径
File file = new File("C:" + File.separator + "Users" + File.separator + "10320" + File.separator + "ideaProjects" + File.separator + "file.txt");
if (!file.getParentFile().exists()) { // 必须保证父目录存在
file.getParentFile().mkdirs() ; // 创建多级父目录
}
String message = "hello world";
try (Writer out = new FileWriter(file)) {
out.write(message);
out.close();
}catch(Exception e){
e.printStackTrace();
}
}
}
总结:
1.不管使用的是字节流还是字符流,其基本的操作流程是一样的:
- 根据文件路径创建File类对象 ;
- 根据字节流或字符流的子类实例化父类对象 ;
- 进行数据的读取或写入操作
- 关闭流(close())
2.在进行文件输出的时候,所有的文件会自动帮助用户创建,不在需要调用createFile()方法手工创建。
3.OutputStream类、InputStream类、Reader类、Writer类都是抽象类,如果要对它们实例化,必须使用它们的子类。
4.在进行IO处理的时候,如果处理的是图片、音乐、文字都可以使用字节流,而只有处理中文的时候才会使用字符流。
5.所有字符流的操作,无论是写入还是输出,数据都要先保存在缓存中,如果字符流不关闭,数据就有可能保存在缓存中并没有输出到目标源。这种情况下就必须使用flush()方法强制刷新才能够得到完整数据
6. InputStream input=new FileInputStream(file);将file对象作为参数传入根据FileInputStream类的构造方法决定