Java IO技术
Java IO技术
java.io包为我们提供了IO相关的API,实现了对所有外部系统的输入输出操作。
数据源
数据源data source,提供数据的原始媒介。常见的数据源有:数据库、文件、其他程序、内存、网络连接、IO设备。 数据源分为:
- 源设备:为程序提供数据,一般对应输入流。
- 目标设备:程序数据的目的地,一般对应输出流。
流
流是一个抽象、动态的概念,是一连串连续动态的数据集合。对于输出流而言,目标数据源就是目的地(dest),我们通过流(A Stream)将程序(Program)中的数据(information)输送到目的数据源(dest)中。
流的分类
- 按流向
- 输入流:数据流向是数据源到程序(以InputStream、Reader结尾的流)。
- 输出流:数据流向是程序到目的地(以OutPutStream、Writer结尾的流)。
- 按处理的数据单元分类
- 字节流:以字节为单位获取数据,命名上以Stream结尾的流一般是字节流,如FileInputStream、FileOutputStream。
- 字符流:以字符为单位获取数据,命名上以Reader/Writer结尾的流一般是字符流,如FileReader、FileWriter。
- 按处理对象
- 节点流:可以直接从数据源或目的地读写数据,如FileInputStream、FileReader、DataInputStream等。
- 处理流:不直接连接到数据源或目的地,是”处理流的流”。通过对其他流的处理提高程序的性能,如BufferedInputStream、BufferedReader等。处理流也叫包装流。
四大IO抽象类
InputStream/OutputStream和Reader/writer类是所有IO流类的抽象父类
- InputStream:此抽象类是表示字节输入流的所有类的父类。继承自InputSteam的流都是用于向程序中输入数据,且数据的单位为字节
- OutputStream:此抽象类是表示字节输出流的所有类的父类。输出流接收输出字节并将这些字节发送到某个目的地。
- Reader:Reader用于读取的字符流抽象类,数据单位为字符。
- writer:Writer用于写入的字符流抽象类,数据单位为字符。
IO标准步骤
- 创建源
- 选择流
- 操作
- 释放
示例:
public class TestIO {
public static void main(String[] args) {
File src = new File("abc.txt");//创建源
InputStream is = null;//选择流
try {
is = new FileInputStream(src);
int temp;
while((temp = is.read()) != -1){//操作
System.out.println((char)temp);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
if (is!=null) {
is.close();//释放
}
}
catch (IOException e) {
e.printStackTrace();
}
}
}
}
文件字节流
FileInputStream通过字节的方式读取文件,适合读取所有类型的文件(图像、视频、文本文件等)。Java也提供了FileReader专门读取文本文件。
示例:
public class TestIO {
public static void main(String[] args) {
File src = new File("abc.txt");//创建源
InputStream is = null;//选择流
try {
is = new FileInputStream(src);
byte[] flush = new byte[1024*5];//一次读5KB
int len = -1;
while((len = is.read(flush)) != -1){
String str = new String(flush, 0, len);
System.out.println(str);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
if (is != null) {
is.close();//释放
}
}
catch (IOException e) {
e.printStackTrace();
}
}
}
}
FileOutputStream 通过字节的方式写数据到文件中,适合所有类型的文件。Java也提供了FileWriter专门写入文本文件。
示例:
public class TestIO {
public static void main(String[] args) {
File dest = new File("dest.txt");//创建源
OutputStream os = null;//选择流
try {
os = new FileOutputStream(dest,true);//追加
String msg = "Hello World";
byte[] datas = msg.getBytes();//转字节
os.write(datas,0,datas.length);//操作
os.flush();//刷新
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
if (os!=null) {
os.close();//释放
}
}
catch (IOException e) {
e.printStackTrace();
}
}
}
}
文件字符流
前面介绍的文件字节流可以处理所有的文件,但是字节流不能很好的处理Unicode字符(两字节),经常会出现“乱码”现象。所以,我们处理文本文件,一般可以使用文件字符流,它以字符为单位进行操作。
FileReader:通过字符的方式读取文件,仅适合字符文件。
FileWriter:通过字节的方式写出或追加数据到文件中,仅适合字符文件。
使用方法与上面大同小异,不再赘述。
字节数组流
ByteArrayInputStream和ByteArrayOutputStream经常用在需要流和数组之间转化的情况,FileInputStream是把文件当做数据源。ByteArrayInputStream则是把内存中的”某个字节数组对象”当做数据源。
ByteArrayInputStream示例:
public class TestIO {
public static void main(String[] args) {
byte[] src = "Hello World!".getBytes();//创建源
InputStream is = null;//选择流
try {
is = new ByteArrayInputStream(src);//追加
byte[] flush = new byte[5];//缓冲容器
int len = -1;
while((len = is.read(flush)) != -1){
String str = new String(flush, 0, len);
System.out.println(str);
}
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
if (is!=null) {
is.close();//释放
}
}
catch (IOException e) {
e.printStackTrace();
}
}
}
}
ByteArrayInputStream注意事项:
- 字节数组不要太大
- GC会自动回收,可以不用手动释放,为了保持风格统一,仍可以写上。
ByteArrayOutputStream示例:
public class TestIO {
public static void main(String[] args) {
byte[] dest = null;//创建源,声明即可
ByteArrayOutputStream os = null;//选择流(要使用其新增方法,不能使用多态了)
try {
os = new ByteArrayOutputStream();//追加
String msg = "Hello World";
byte[] datas = msg.getBytes();//转字节
os.write(datas,0,datas.length);//操作
os.flush();//刷新
dest = os.toByteArray();//可以获取数据看看
System.out.println(dest.length + "--->" + new String(dest,0,os.));
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
if (os!=null) {
os.close();//释放
}
}
catch (IOException e) {
e.printStackTrace();
}
}
}
}
ByteArrayOutputStream注意事项:
- 不用创建源,有内部维护,只要声明即可。
- 也无需手动释放。
- 最后可使用toByteArray()获取数据。
缓冲字节流
Java缓冲流本身并不具有IO流的读取与写入功能,只是在别的流(节点流或其他处理流)上加上缓冲功能提高效率,就像是把别的流包装起来一样,因此缓冲流是一种处理流(包装流)。
当对文件或者其他数据源进行频繁的读写操作时,效率比较低,这时如果使用缓冲流就能够更高效的读写信息。因为缓冲流是先将数据缓存起来,然后当缓存区存满后或者手动刷新时再一次性的读取到程序或写入目的地。
BufferedInputStream和BufferedOutputStream这两个流是缓冲字节流,通过内部缓存数组来提高操作流的效率。
BufferedInputStream使用示例:
//将文件字节流FileInputStream第七行直接套一层即可
is = new FileInputStream(src);
//like this
is = new BufferedInputStream(FileInputStream(src));
BufferedOutputStream使用示例:
//将文件字节流FileOutputStream第七行直接套一层即可
os = new FileOutputStream(dest);
//like this
os = new BufferedOutputStream(FileOutputStream(dest,true));
注意:
- 在关闭流时,应该先关闭最外层的包装流,即“后开的先关闭”。
- 缓存区的大小默认是8192字节,也可以使用其它的构造方法自己指定大小。
缓冲字符流
BufferedReader/BufferedWriter增加了缓存机制,高效,且提供了按行读取方法。使用方法同缓冲字节流一样。
BufferedReader逐行读取使用示例:
//在文件字节符FileReader外面直接套一层即可
is = new FileReader(src);
//like this
is = new BufferedReader(FileReader(src));
//逐行读取方法:
while((line=reader.readLine())!=null){}
BufferedWriter用法大同小异。
转换流
InputStreamReader/OutputStreamWriter用来实现将字节流转化成字符流,且可以指定字符集。例如键盘输入时需要使用转换。
public class Test {
public static void main(String[] args) {
try(BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(System.out));){
String msg = "";
while (!msg.equals("exit")){//输入exit退出
msg=reader.readLine();//循环读取
writer.write(msg);//循环写入
writer.newLine();
writer.flush();//强制刷新,否则缓冲区不满不输出
}
}catch (IOException e){
System.out.println("操作异常");
}
}
}
数据流
数据流将“基本数据类型与字符串类型”作为数据源,从而允许程序以与机器无关的方式从底层输入输出流中操作Java基本数据类型与字符串类型。
DataInputStream和DataOutputStream提供了可以存取与机器无关的所有Java基础类型数据(如:int、double、String等)的方法。
DataInputStream和DataOutputStream是处理流,可以对其他节点流或处理流进行包装,增加一些更灵活、更高效的功能。
示例:
public class Test {
public static void main(String[] args) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(baos);
try {
dos.writeUTF("你好世界");
dos.writeInt(18);
dos.writeBoolean(false);
dos.writeChar('a');
dos.flush();
byte[] datas = baos.toByteArray();
DataInputStream dis = new DataInputStream(new ByteArrayInputStream(datas));
String msg = dis.readUTF();
int age = dis.readInt();
boolean flag = dis.readBoolean();
char ch = dis.readChar();
System.out.println(msg);
System.out.println(age);
System.out.println(flag);
System.out.println(ch);
}
catch (IOException e) {
e.printStackTrace();
}
}
}
对象流
数据流只能实现对基本数据类型和字符串类型的读写,并不能读取对象(字符串除外),如果要对某个对象进行读写操作,我们需要ObjectInputStream/ObjectOutputStream。上述二者以“对象”为数据源,但是必须将传输的对象进行序列化(Serialization)与反序列(Desserialization)化操作。

使用方法与数据流大同小异,但需要注意,不是所有类都可以序列化,有Serializable方法的才可以序列化。
CommonsIO
CommonsIO是由Apache软件基金会支持的项目,可在Apache官网对应CommonsIO项目下载。
将其加入IDEA的模块依赖即可使用:

FileUtils
常用方法:
- cleanDirectory:清空目录,但不删除目录。
- contentEquals:比较两个文件的内容是否相同。
- copyDirectory:将一个目录内容拷贝到另一个目录。可以通过FileFilter过滤需要拷贝的 文件。
- copyFile:将一个文件拷贝到一个新的地址。
- copyFileToDirectory:将一个文件拷贝到某个目录下。
- copyInputStreamToFile:将一个输入流中的内容拷贝到某个文件。
- deleteDirectory:删除目录。
- deleteQuietly:删除文件。
- listFiles:列出指定目录下的所有文件。
- openInputSteam:打开指定文件的输入流。
- readFileToString:将文件内容作为字符串返回。
- readLines:将文件内容按行返回到一个字符串数组中。
- size:返回文件或目录的大小。
- write:将字符串内容直接写到文件中。
- writeByteArrayToFile:将字节数组内容写到文件中。
- writeLines:将容器中的元素的toString方法返回的内容依次写入文件中。
- writeStringToFile:将字符串内容写到文件中。
使用示例:
public class Test {
public static void main(String[] args) throws IOException {
long len = FileUtils.sizeOf(new File("TestWrapped.java"));
System.out.println(len);
List<String> msgs = FileUtils.readLines(new File("emp.txt"),"UTF-8");
for(String string : msgs){
System.out.println(string);
}
FileUtils.copyFile(new File("p.png"),new File("p_copy.png"));
FileUtils.copyFileToDirectory(new File("p.png"),new File("lib"));
}
}
更多方法及其使用查看API文档。
IOUtils
常用方法:
- buffer方法:将传入的流进行包装,变成缓冲流。并可以通过参数指定缓冲大小
- closeQueitly方法:关闭流。
- contentEquals方法:比较两个流中的内容是否一致。
- copy方法:将输入流中的内容拷贝到输出流中,并可以指定字符编码。
- copyLarge方法:将输入流中的内容拷贝到输出流中,适合大于2G内容的拷贝。
- lineIterator方法:返回可以迭代每一行内容的迭代器。
- read方法:将输入流中的部分内容读入到字节数组中。
- readFully方法:将输入流中的所有内容读入到字节数组中。
- readLine方法:读入输入流内容中的一行。
- toBufferedInputStream,toBufferedReader:将输入转为带缓存的输入流。
- toByteArray,toCharArray:将输入流的内容转为字节数组、字符数组。
- toString:将输入流或数组中的内容转化为字符串。
- write方法:向流里面写入内容。
- writeLine方法:向流里面写入一行内容。
使用示例:
public class Test {
public static void main(String[] args) throws IOException {
String content = IOUtils.toString(new FileInputStream("a.txt"),"gbk");
System.out.println(content);
}
}
更多方法及其使用查看API文档。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了