概览
Java I/O操作指的是数据的输入/输出操作。
Java的I/O操作类在java.io包中,主要分以下几种:
- 基于字节操作的I/O接口: InputStream和OutputStream
- 基于字符操作的I/O接口: Writer和Reader
- 基于磁盘操作的I/O接口: File
一、核心类介绍
- 基于字节的I/O操作,核心是操作字节数组byte[],可以操作任何类型的流数据
- 基于字符的I/O操作,核心是操作字符数组char[],只能操作字符类型的流数据,如果是非字符的流数据(如图片、视频等)会变成乱码
1、字节输入流
类 | 功能 | 说明 |
---|---|---|
ByteArrayInputStream | 将内存的缓冲区当做InputStream使用 | 将其与FilterInputStream对象相连,将字节流存入文件中 |
FileInputStream | 从文件中读取信息 | 将文件对象File转换成输入流,以读取文件中数据 |
FilterInputStream | 抽象类,作为装饰器的接口,为其他的InputStream类提供有用的功能 | |
BufferedInputStream | 提供了缓冲区的操作,提高IO的性能;为传入的输入流添加缓冲功能 | FilterInputStream子类 |
DataInputStream | 与DataOutputStream搭配使用,按照移植方式从流读取基本数据类型;包含用于读取基本数据类型的全部接口 | FilterInputStream子类 |
2、字节输出流
类 | 功能 | 说明 |
---|---|---|
ByteArrayOutputStream | 在内存中创建缓冲区。所有送往流的数据都要放置在此缓冲区 | 可以方便的将输入流转换成字节数组 |
FileOutputStream | 用于将信息写入文件 | |
FilterOutputStream | 抽象类,作为装饰器的接口,为其他OutputStream提供有用的功能 | |
BufferedOutputStream | 提供了缓冲区的操作,提高IO的性能;为传入的输出流添加缓冲功能,可以调用flush()清空缓冲区 | FilterOutputStream子类 |
DataOutputStream | 与DataInputStream搭配使用,可以按照移植方式向流中写入基本数据类型;包含用于写入基本数据类型的全部接口 | FilterOutputStream子类 |
3、字符输入流
类 | 功能 | 说明 |
---|---|---|
InputStreamReader | 将字节输入流InputStream转换成字符输入流 | |
FileReader | 将文件对象File转换成字符输入流 | InputStreamReader的子类 |
BufferedReader | 提供缓冲区功能,提高字符输入流Reader的操作性能 | |
StringReader | 将字符串转换成字符流操作 |
4、字符输出流
类 | 功能 | 说明 |
---|---|---|
OutputStreamWriter | 将字节输出流OutputStream转换成字符输出流 | |
FileWriter | 将文件对象File转换成字符输出流 | OutputStreamWriter的子类 |
BufferedWriter | 提供缓冲区功能,提高字符输出流Writer的操作性能 | |
StringWriter | 将字符串转换成字符流操作 |
二、关键操作介绍
1、关闭流
所有数据流在操作完成后,都需要调用close方法关闭,在1.7及之后建议使用try-with-resources
语句来使用流,这样可以避免显示的调用close()方法,减少一些重复代码,在操作完成后会自动调用close方法。
try-with-resources
语句可以自动close所有实现接口java.io.Closeable
的子类对象。
try (BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file))) {bos.write(content.getBytes());bos.flush();}
2、刷新缓存
flush()方法用来强制要求OutputStream对象将暂存于内部缓冲区的数据立即进行实际的写入(一般情况下不需要手动的调用该方法,在内部缓冲区填充满了之后,会自动执行实际的写入操作,在调用close()方法时也会自动调用flush()方法)
3、序列化流和反序列化流
对象的序列化就是将对象转化为byte序列,反之叫做反序列化,ObjectOutputStream是序列化流,ObjectInputStream是反序列化流。
被操作的对象必须实现序列化接口Serializable,如果不想某个字段进行序列化,可以使用transient来修饰字段,使得该字段不进行序列化,也可以通过重写writeObjectOverride()
和readObjectOverride()
方法来进行手动序列化。
静态变量也不能进行序列化,因为所有的对象都共享同一份静态变量值
1)ObjectOutputStream序列化流
主要的方法是writeObject,存储对象的类、类的签名以及这个类及其父类中所有非静态和非瞬时的字段的值
public final void writeObject(Object obj) throws IOException {if (enableOverride) {writeObjectOverride(obj);return;}try {writeObject0(obj, false);} catch (IOException ex) {if (depth == 0) {writeFatalException(ex);}throw ex;}
}
2)ObjectInputStream反序列化流
主要的方法是readObject,读回对象的类、类的签名以及这个类及其父类中所有非静态和非瞬时的字段的值
public final Object readObject()throws IOException, ClassNotFoundException{if (enableOverride) {return readObjectOverride();}// if nested read, passHandle contains handle of enclosing objectint outerHandle = passHandle;try {Object obj = readObject0(false);handles.markDependency(outerHandle, passHandle);ClassNotFoundException ex = handles.lookupException(passHandle);if (ex != null) {throw ex;}if (depth == 0) {vlist.doCallbacks();}return obj;} finally {passHandle = outerHandle;if (closed && depth == 0) {clear();}}}
三、代码示例
import org.springframework.util.StopWatch;
import java.io.*;
public class FileUtilTest {/*** 复制文件*/public static void copyFile(String fromFileName, String toFileName) throws Exception {File fromFile = new File(fromFileName);File toFile = new File(toFileName);StopWatch watch = new StopWatch("fileTest");watch.start("copy");if (!fromFile.exists()) {System.out.println("源文件不存在");System.exit(1);}if (!toFile.getParentFile().exists()) {toFile.getParentFile().mkdirs();}try (InputStream is = new FileInputStream(fromFile);OutputStream os = new FileOutputStream(toFile)) {int temp = 0;byte[] data = new byte[4096];while ((temp = is.read(data)) != -1) {os.write(data, 0, temp);}watch.stop();System.out.println(watch.prettyPrint());}}/*** 通过字符流将字符串写入到文件中*/public static void write(String fileName, String content) throws IOException {File file = new File(fileName);if (!file.getParentFile().exists()) {file.getParentFile().mkdirs();}try (Writer out = new FileWriter(file)) {out.write(content);out.flush();}}/*** 通过字节流将字符串写入到文件中,增加缓冲区功能*/public static void writeBuffer(String fileName, String content) throws IOException {File file = new File(fileName);if (!file.getParentFile().exists()) {file.getParentFile().mkdirs();}try (BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file))) {bos.write(content.getBytes());bos.flush();}}/*** 通过字符流将字符串写入到文件中,增加缓冲区功能*/public static void writeBufferedWriter(String fileName, String content) {File file = new File(fileName);if (!file.getParentFile().exists()) {file.getParentFile().mkdirs();}try (BufferedWriter bw = new BufferedWriter(new FileWriter(file))) {bw.write(content);bw.flush();} catch (Exception e) {e.printStackTrace();}}/*** 通过字符流,从文件中读取字符串内容*/public static void readChar(String fileName) {File file = new File(fileName);if (!file.exists()) {return;}try (Reader in = new FileReader(file)) {char[] data = new char[4096];int len;StringBuilder sb = new StringBuilder();while ((len = in.read(data)) != -1) {sb.append(new String(data, 0, len));}in.close();System.out.println(sb);} catch (Exception e) {e.printStackTrace();}}/*** 通过字节流,从文件中读取字符串内容*/public static void readByte(String fileName) throws IOException {File file = new File(fileName);if (!file.exists()) {return;}try (InputStream in = new FileInputStream(file)) {byte[] data = new byte[4096];int len;StringBuilder sb = new StringBuilder();while ((len = in.read(data)) != -1) {sb.append(new String(data, 0, len));}System.out.println(sb);} catch (Exception e) {e.printStackTrace();}}/*** 通过字符流,从文件中读取字符串内容,增加缓冲区功能*/public static void readBufferReader(String fileName) throws Exception {File file = new File(fileName);if (!file.exists()) {return;}try (BufferedReader bufferedReader = new BufferedReader(new FileReader(file))) {String line;while ((line = bufferedReader.readLine()) != null) {System.out.println(line);}}}/*** 通过字节流,从文件中读取字符串内容,增加缓冲区功能*/public static void readBuffer(String fileName) throws Exception {File file = new File(fileName);if (!file.exists()) {return;}try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file))) {int len;byte[] data = new byte[4096];while ((len = bis.read(data)) != -1) {System.out.println(new String(data, 0, len));}}}/*** 将文件内容转换成字节数组*/public static byte[] file2OutStream(String fileName) throws Exception {File file = new File(fileName);if (!file.exists()) {return null;}try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));ByteArrayOutputStream bos = new ByteArrayOutputStream()) {int len;byte[] data = new byte[4096];while ((len = bis.read(data)) != -1) {bos.write(data, 0, len);}return bos.toByteArray();}}/*** 将Java对象序列化存储在到文件中*/public static void objWrite(String fileName) {File file = new File(fileName);try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(file))) {oos.writeObject("Hello ,World");oos.writeBoolean(false);} catch (Exception e) {e.printStackTrace();}}/*** 从序列化文件中反序列化出Java对象*/public static void objRead(String fileName) {File file = new File(fileName);try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file))) {Object o = ois.readObject();System.out.println(o.getClass());System.out.println("o = " + o);System.out.println("ois.readBoolean() = " + ois.readBoolean());} catch (Exception e) {e.printStackTrace();}}}