分类
在Java中IO流可按多种方式进行分类:
1)按数据流向分类可分为:
-
输入流,从外部读取数据输入到程序(内存)中,例如读取本地文件;
-
输出流,从程序(内存)中输出数据到外部,例如将字符串保存到本地文件。
2)按处理的数据类型分类可分为:
-
字节流,以字节(8bit)为单位操作数据,能处理所有类型的数据(如图片、视频等);
-
字符流,以字符(16bit)为单位操作数据,只能处理字符类型的数据(如TXT等纯文本类)。
既然字节流能处理所有类型,为什么还要字符流呢?因为Java中字符采用Unicode标准,而字节流并不能直接操作Unicode字符;为此,Java中引入了处理字符的流,其本质就是基于字节流读取后,先查询指定的编码表获取对应文字再进行操作,所以在处理字符上优于字节流。
类图结构
Java中所有流都源于4个抽象基类:
输入流 | 输出流 | |
---|---|---|
字节流 | InputStream | OutputStream |
字符流 | Reader | Writer |
File类
在了解IO具体操作前,需要先了解一下File类,File类提供了详细的文件操作功能,弥补了IO只能够操作数据的不足,下面是通过File类创建文件及文件夹的示例:
import java.io.File;
import java.io.IOException;
public class FileDemo {
public static void main(String[] args) {
//创建File对象,指定路径
File file = new File("D:/a.txt");
File file1 = new File("D:/a");
try {
//通过File对象创建文件
file.createNewFile();
//通过File对象创建文件夹
file1.mkdir();
} catch (IOException e) {
e.printStackTrace();
}
}
}
File类还提供了诸如删除文件、获取文件信息等相关操作函数,具体可查阅File类API。
常用IO类示例
FileInputStream、FileOutputStrem
FileInputStream、FileOutputStrem是比较常用的字节输入和输出流,下面使用它们完成文本数据的输入输出:
public static void main(String[] args) {
//创建file对象指向之前创建的a.txt文本
File file = new File("D:/a.txt");
//创建读取文件的byte数组,1024即为1kb
byte[] bytes = new byte[1024];
//创建字节输出流输入流,指向之前使用File类创建的a.txt文本
try (FileOutputStream fileOutputStream = new FileOutputStream(file,true);
FileInputStream fileInputStream = new FileInputStream(file)) {
//在文本中写入abc
fileOutputStream.write("abc".getBytes());
//read()方法不传参时,读取1字节,并强转为int返回
//read()方法传参为byte数组时,读取byte数组长度的字节,并返回读取的字节数
// 将读取到的内容放在byte数组中并且返回读取内容的字节数
int length = fileInputStream.read(bytes);
System.out.println(length); //3
System.out.println(new String(bytes)); //abc
} catch (IOException e) {
e.printStackTrace();
}
}
这里创建输出流 new FileOutputStream(file,true) 时,传入的第二个参数true,表示输出数据时在文件原有的基础上追加,如果忽略不传的话默认为false,如 new FileOutputStream(file),则是覆盖掉文件原始内容。
OutputStreamWriter
比较常见的字符输出流,上面说到过Java字符流的本质就是字节流加码表,所以这里创建字符流时,需要传入字节流对象和字符集编码(不传则默认使用平台编码),输出文本示例:
public static void main(String[] args) {
//创建file对象指向之前创建的a.txt文本
File file = new File("D:/a.txt");
//创建字符流
try(FileOutputStream fileOutputStream = new FileOutputStream(file);
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream,"gbk")){
//输出数据到文本
outputStreamWriter.write("好好学习,天天向上!");
} catch (IOException e) {
e.printStackTrace();
}
}
InputStreamReader
常见的字符输入流,需要传入字节流对象和编码(不传则默认使用平台编码),输入文本示例:
public static void main(String[] args) {
//创建file对象指向之前创建的a.txt文本
File file = new File("D:/a.txt");
//创建存放数据的字符数组
char[] c = new char[64];
try(FileInputStream fileInputStream = new FileInputStream(file);
//创建输入字符流
InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream,"gbk")){
//从文本中读取数据到char数组,并返回读取字符数
int read = inputStreamReader.read(c);
System.out.println(read); //输出10
System.out.println(new String(c)); //输出 好好学习,天天向上!
} catch (IOException e) {
e.printStackTrace();
}
}
BufferedReader
使用处理流BufferedReader对InputStreamReader进行封装,从字符输入流中读取文本并缓冲字符,便可调用BufferedReader的readLine()方法进行整行数据的读取:
public static void main(String[] args) {
//创建file对象指向之前创建的a.txt文本
File file = new File("D:/a.txt");
try(FileInputStream fileInputStream = new FileInputStream(file);
InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream, "gbk");
//创建BufferedReader
BufferedReader bufferedReader = new BufferedReader(inputStreamReader)){
String line = null;
//整行读取数据
while ((line=bufferedReader.readLine())!= null){
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
}
这里补充一点,JavaIO流按功能不同可分为节点流和处理流,节点流是真正传输数据的流对象,用于向特定的一个地方(节点)读写数据,例如FileInputStream;而处理流是对节点流的封装,使用外层的处理流读写数据,本质上是利用节点流的功能,外层的处理流可以提供额外的功能,如BufferedReader;上面代码中就是使用BufferedReader对FileInputStream进行了封装,同理你也可以根据需要的功能使用其他的处理流进行更多的封装和组合。
IO流的关闭
Java不会回收流对象,如果不关闭流对象,可能会造成内存泄漏;在jdk1.7之前,我们需要手动调用close方法来关闭流,而从jdk1.7开始,Java提供了新的 try-with-resources 语句,我们只需要把创建语句放在try()中,Java就能确保在语句末尾关闭每个资源对象。示例:
try (FileOutputStream fileOutputStream = new FileOutputStream(file,true);
FileInputStream fileInputStream = new FileInputStream(file)) {//多个对象以“;”隔开
//code......
}catch (IOException e) {
e.printStackTrace();
}