一个程序运行时,变量、数组和对象中存储的数据都是存在于内存条中的,当程序运行结束,或者计算机断电时,它们就会消失。而现在的项目工程,往往涉及到大量需要长时间保存的数据,而磁盘文件能够永久保存数据,所以数据处理和文件操作知识就密切相关了。
掌握文件操作,能够大大提高我们对数据的处理能力。所以今天鸭哥想和大家一起,聊聊文件操作那些事儿~
# 基本概念
流是一组有序的数据序列,分为输入流和输出流。输入流表示从一个源读取数据,输出流表示向一个目的地写数据。虽然流通常与文件存取有关,但是程序的源和目的地也可以是键盘、鼠标、内存或显示器窗口。
InputStream 类
InputStream 类是字节输入流的抽象类,是所有字节输入流的父类。该类中所有方法遇到错误都会引发 IOException 异常。
Reader 类
InputStream 是用来处理字节的,并不适合用来处理字符文本,Java 为字符文本的输入专门提供了单独的类 Reader,Reader 类是字符输入流的抽象类,所有字符输入流的实现都是它的子类。
OutputStream 类
OutputStream 类是字节输出流的抽象类,类中的所有方法均返回void,在遇到错误时会引发 IOException。
Writer 类
同样,Java 提供了字符输出流的抽象类 Writer,所有字符输出类的实现都是它的子类。为了让大家一目了然,贴心的鸭哥特意整理了一张描述I/O(Input/Output)流的类层次图(建议收藏保存)
案例演示:文件的简单复制
我们最常用的两个流就是 FileInputStream 和 FileOutputStream。FileInputStream 用于从文件读取数据,它的对象可以用关键字 new 来创建。FileOutputStream 用来创建一个文件并向文件中写数据。如果该流在打开文件进行输出前,目标文件不存在,那么该流会创建该文件。
下面的代码实现了文件的简单复制功能,
import java.io.*; public class IOTest { public static void main(String[] args) { //创建源文件及复制文件的对象 File sourcefile = new File("E:/duckAndJava/IO/testFile.txt"); File copyfile = new File("E:/duckAndJava/IO/copiedTestFile.txt"); FileInputStream fileInputStream = null; // 从文件中读数据 FileOutputStream fileOutputStream = null; // 用于把数据写入文件 BufferedWriter bufferedWriter = null; // 用于把数据写入文件 try { if (!sourcefile.exists()) { sourcefile.createNewFile(); bufferedWriter = new BufferedWriter(new FileWriter(sourcefile)); // bufferedwriter 自动追加数据 String s = new String(" I love duckAndJava."); char bchar[] = s.toCharArray(); for (int i = 0; i < 3; i++) { // 往文件中写数据 bufferedWriter.write(bchar, 0, bchar.length); bufferedWriter.write("\n"); } // 写完之后,才能关闭流 bufferedWriter.flush(); bufferedWriter.close(); } //复制文件 copyfile.createNewFile(); fileInputStream = new FileInputStream(sourcefile); //另一种创建方法:InputStream fileInputStream = new FileInputStream("E:/duckAndJava/IO/testFile.txt"); fileOutputStream = new FileOutputStream(copyfile); //另一种创建方法:OutputStream fileOutputStream = new FileOutputStream("E:/duckAndJava/IO/copiedTestFile.txt") byte b[] = new byte[1024]; int len = b.length; while ((len = fileInputStream.read(b, 0, len)) > 0) {//到达流末尾时,返回-1,跳出循环 fileOutputStream.write(b, 0, len); fileOutputStream.flush(); } System.out.println("复制文件完成"); fileInputStream.close(); fileOutputStream.close(); } catch (IOException e) { e.printStackTrace(); } } }
上面代码的功能实现可以分为三个部分:
- 如果源文件不存在,我们就创建源文件,并向文件中写入数据;
- 从源文件中读取输入流到字节数组中;
- 将字节数组中通过输出流写入到复制文件中
# 拓展
细心的读者可能已经发现了,鸭哥在文件复制的代码中,除了使用FileInputStream类 和 FileOutputStream类,还使用了 File 类。File 类是 java.io 包中唯一代表磁盘文件本身的对象。我们可以通过File类的方法,实现创建。删除和重命名文件等操作,而且这些操作与平台无关。建议大家多多学习相关操作~
在源文件不存在,创建源文件写数据时,鸭哥使用了 BufferedWriter ,它是 Writer 的子类,是以字符流的形式写入了源文件的数据。
而复制源文件时,鸭哥使用的则是 FileInputStream 的 read() 方法,和 FileOutputStream 的 write() 方法,它们都属于字节流操作。
一个样例,两类数据流(字符和字节),三个 I/O 类。本文的样例包含了很多值得细细品味的内容,你体会到鸭哥样例设计的用心良苦了吗?