1、概念
Java的核心库java.io提供了全面的IO接口。包括:文件读写、标准设备输出等。Java中IO是以流为基础进行输入输出的,所有数据被串行化写入输出流,或者从输入流读入。
2、描述
3、Java流输入输出原理
Java把这些不同来源和目标的数据都统一抽象为数据流。Java语言的输入输出功能是十分强大而灵活的,美中不足的是看上去输入输出的代码并不是很简洁,因为你往往需要包装许多不同的对象。
在Java类库中,IO部分的内容是很庞大的,因为它涉及的领域很广泛:标准输入输出,文件的操作,网络上的数据流,字符串流,对象流,zip文件流。
4、Java流的分类
1)按流向分:
输入流: 程序可以从中读取数据的流。
输出流: 程序能向其中写入数据的流。
2)按数据传输单位分:
字节流: 以字节为单位传输数据的流
字符流: 以字符为单位传输数据的流
3)按功能分:
节点流: 用于直接操作目标设备的流
过滤流: 是对一个已存在的流的链接和封装,通过对数据进行处理为程序提供功能强大、灵活的读写功能。
5、java.io常用类
JDK所提供的所有流类位于java.io包中,都分别继承自以下四种抽象流类。
InputStream:继承自InputStream的流都是用于向程序中输入数据的,且数据单位都是字节(8位)。
OutputStream:继承自OutputStream的流都是程序用于向外输出数据的,且数据单位都是字节(8位)。
Reader:继承自Reader的流都是用于向程序中输入数据的,且数据单位都是字符(16位)。
Writer:继承自Writer的流都是程序用于向外输出数据的,且数据单位都是字符(16位)。
6、接口摘要
Closeable |
Closeable 是可以关闭的数据源或目标。 |
DataInput |
DataInput 接口用于从二进制流中读取字节,并根据所有 Java 基本类型数据进行重构。 |
DataOutput |
DataOutput 接口用于将数据从任意 Java 基本类型转换为一系列字节,并将这些字节写入二进制流。 |
Externalizable |
Externalizable 实例类的唯一特性是可以被写入序列化流中,该类负责保存和恢复实例内容。 |
FileFilter |
用于抽象路径名的过滤器。 |
FilenameFilter |
实现此接口的类实例可用于过滤器文件名。 |
Flushable |
Flushable 是可刷新数据的目标地。 |
ObjectInput |
ObjectInput 扩展 DataInput 接口以包含对象的读操作。 |
ObjectInputValidation |
允许验证图形中对象的回调接口。 |
ObjectOutput |
ObjectOutput 扩展 DataOutput 接口以包含对象的写入操作。 |
ObjectStreamConstants |
写入 Object Serialization Stream 的常量。 |
Serializable |
类通过实现 java.io.Serializable 接口以启用其序列化功能。 |
7、类摘要
BufferedInputStream |
BufferedInputStream 为另一个输入流添加一些功能,即缓冲输入以及支持 mark 和 reset 方法的能力。 |
BufferedOutputStream |
该类实现缓冲的输出流。 |
BufferedReader |
从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取。 |
将文本写入字符输出流,缓冲各个字符,从而提供单个字符、数组和字符串的高效写入。 |
|
ByteArrayInputStream |
ByteArrayInputStream 包含一个内部缓冲区,该缓冲区包含从流中读取的字节。 |
ByteArrayOutputStream |
此类实现了一个输出流,其中的数据被写入一个 byte 数组。 |
CharArrayReader |
此类实现一个可用作字符输入流的字符缓冲区。 |
CharArrayWriter |
此类实现一个可用作 Writer 的字符缓冲区。 |
此类包含多个方法,可访问与当前 Java 虚拟机关联的基于字符的控制台设备(如果有)。 |
|
数据输入流允许应用程序以与机器无关方式从底层输入流中读取基本 Java 数据类型。 |
|
DataOutputStream |
数据输出流允许应用程序以适当方式将基本 Java 数据类型写入输出流中。 |
File |
文件和目录路径名的抽象表示形式。 |
FileDescriptor |
|
FileInputStream |
FileInputStream 从文件系统中的某个文件中获得输入字节。 |
文件输出流是用于将数据写入 File 或 FileDescriptor 的输出流。 |
|
FilePermission |
此类表示对文件和目录的访问。 |
FileReader |
用来读取字符文件的便捷类。 |
用来写入字符文件的便捷类。 |
|
FilterInputStream |
FilterInputStream 包含其他一些输入流,它将这些流用作其基本数据源,它可以直接传输数据或提供一些额外的功能。 |
此类是过滤输出流的所有类的超类。 |
|
FilterReader |
用于读取已过滤的字符流的抽象类。 |
FilterWriter |
用于写入已过滤的字符流的抽象类。 |
此抽象类是表示字节输入流的所有类的超类。 |
|
InputStreamReader |
InputStreamReader 是字节流通向字符流的桥梁:它使用指定的 charset 读取字节并将其解码为字符。 |
LineNumberInputStream |
已过时。此类错误假定字节能充分表示字符。 |
8、代码实现
package com.liuxd.io;
import java.io.*;
/**
* Created by Liuxd on 2018/8/21.
*/
public class TestIo {
/**
* 字节流
* @param src
* @param dest
*/
private static void copyByInOutputStream(String src, String dest) {
InputStream in = null;
OutputStream out = null;
try {
//读取源文件字节流
in = new FileInputStream(src);
//写入目标文件
out = new FileOutputStream(dest);
//每次取字节数
byte[] bytes = new byte[1024];
//接受读取源的内容(n就代表的相关数据,只不过是数字的形式)
int num;
//循环取出数据
while ((num = in.read(bytes, 0, bytes.length)) != -1) {
String message = new String(bytes, 0, num, "UTF-8");
// System.out.println(message);
//写入目标文件
out.write(bytes, 0, num);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//关闭写入流
if (null != in) {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
//关闭读取源流
if (null != out) {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/**
* 缓存字节流--推荐
* @param src
* @param dest
*/
private static void copyByBufferedInOutputStream(String src, String dest) {
try {
//读取源文件缓存字节流
BufferedInputStream in = new BufferedInputStream(new FileInputStream(src));
//写入目标文件
BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(dest));
//每次读取源字节数
byte[] bytes = new byte[1024];
int n;
//循环读取源数据
while ((n = in.read(bytes, 0, bytes.length)) != -1) {
//转换成字符串
String message = new String(bytes, 0, n, "UTF-8");
// System.out.println(message);
//写入相关文件
out.write(bytes, 0, n);
}
//清楚缓存
out.flush();
//关闭流
in.close();
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 字节流,不推荐,因为不能直接按照字节长度进行读写
* @param src
* @param dest
*/
private static void copyByInOutputStreamReader(String src, String dest) {
try {
//读取源文件
InputStreamReader in = new InputStreamReader(new FileInputStream(src), "UTF-8");
//写入目标文件
OutputStreamWriter out = new OutputStreamWriter(new FileOutputStream(dest));
int length;
//循环读取源
while ((length = in.read()) != -1) {
// System.out.println(length);
//写入目标文件
out.write(length);
}
//清除缓存
out.flush();
//关闭流
in.close();
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 缓存流,可轻松实现按行读取
* @param src
* @param dest
*/
private static void copyByBufferedReaderWriter(String src, String dest) {
try {
//读取源文件(字符流)
BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(src), "UTF-8"));
//写入相应的文件
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(dest), "UTF-8"));
//循环读取源数据
String message;
while ((message = in.readLine()) != null) {
// System.out.println(message);
//写入目标文件
out.write(message);
out.newLine();
}
//清楚缓存
out.flush();
//关闭流
in.close();
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* PrintWriter
* @param src
* @param dest
*/
private static void copyByInputStreamReaderPrintWriter(String src, String dest) {
try {
//读取源文件字节流
Reader in = new InputStreamReader(new FileInputStream(src), "UTF-8");
//写入目标文件
PrintWriter out = new PrintWriter(new FileWriter(dest));
//循环读取源数据
int length;
while ((length = in.read()) != -1) {
// System.out.println(length);
//写入相关文件
out.write(length);
}
//清除缓存
out.flush();
//关写入闭流
in.close();
//关读取闭流
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
String src = "E:\\You Took My Heart Away.flac";
String dest = "E:\\You Took My Heart Away Dest.flac";
String dest1 = "E:\\You Took My Heart Away Dest2.flac";
String dest2 = "E:\\You Took My Heart Away Dest3.flac";
String dest3 = "E:\\You Took My Heart Away DesT4.flac";
String dest4 = "E:\\You Took My Heart Away DesT5.flac";
long beginTime = System.currentTimeMillis();
TestIo.copyByInOutputStream(src, dest);
long endTime = System.currentTimeMillis();
System.out.println("copyByInOutputStream 字节流---耗时:" + (endTime - beginTime) + "毫秒");
long beginTime1 = System.currentTimeMillis();
TestIo.copyByInOutputStream(src, dest1);
long endTime1 = System.currentTimeMillis();
System.out.println("copyByInOutputStream 缓存字节流---耗时:" + (endTime1 - beginTime1) + "毫秒");
long beginTime2 = System.currentTimeMillis();
TestIo.copyByInOutputStreamReader(src, dest2);
long endTime2 = System.currentTimeMillis();
System.out.println("copyByInOutputStreamReader 字节流---耗时:" + (endTime2 - beginTime2) + "毫秒");
long beginTime3 = System.currentTimeMillis();
TestIo.copyByBufferedReaderWriter(src, dest3);
long endTime3 = System.currentTimeMillis();
System.out.println("copyByBufferedReaderWriter 缓存字节流---耗时:" + (endTime3 - beginTime3) + "毫秒");
long beginTime4 = System.currentTimeMillis();
TestIo.copyByInputStreamReaderPrintWriter(src, dest4);
long endTime4 = System.currentTimeMillis();
System.out.println("copyByInputStreamReaderPrintWriter PrintWriter---耗时:" + (endTime4 - beginTime4) + "毫秒");
}
}
输出结果:
copyByInOutputStream 字节流---耗时:823毫秒
copyByInOutputStream 缓存字节流---耗时:668毫秒
copyByInOutputStreamReader 字节流---耗时:3483毫秒
copyByBufferedReaderWriter 缓存字节流---耗时:1182毫秒
copyByInputStreamReaderPrintWriter PrintWriter---耗时:3178毫秒
源文件与copy后的文件截图,请对照文件大小: