初识Java中的IO流
Java以流的形式处理数据的输入和输出。这些接口和类的定义被防放在java.io
包下。
按照数据流动的方向,可以分为输入流和输出流,这里的输入/输出是以内存中的程序(进程)为基准的。按照流中数据的最小单位来分类,可以分为字节流和字符流。字节流适合操作所有类型的文件,而字符流只适合操作纯文本文件。
总的来说,如上图所示,Java的IO流分为四大类接口:字节输入流、字节输出流、字符输入流、字符输出流。这四个抽象类分别有对应的实现类。
注意IO流都实现了Closeable
接口,这意味着其对象在使用完成之后都需要调用close()
方法来关闭,即释放资源(也就是说IO流可以看作是一种资源)。实例化IO流对象和使用的过程中都可能会产生异常,在流对象正常关闭之前,如果因为异常而导致程序退出,则该流对象则无法被释放(事实上,所有资源都是如此)。因此,最好使用try-catch-finally语句块或try-with-resource语句块来让Java虚拟机自动管理资源的释放操作。
字节流FileInputStream
和FileOutputStream
构造器提供了使用File
对象或以字符串形式指定文件路径的两种构造器。其提供了读取和写入数据的接口,既可以每次只读/写一个字节,也可以使用字节数组作为缓冲每次读/写多个字节。一般来说使用缓冲数组读写效率更高(因为读写相同大小的数据时系统调用次数更少),缓冲数组越大,读写效率越高(不过效率增长并不是线性的)。
try (InputStream is = new FileInputStream("input/file/path"); OutputStream os = new FileOutputStream("output/file/path")) { int len; byte[] buffer = new byte[1024]; // 缓冲数组的大小为1KB while ((len = is.read(buffer)) !=-1){ os.write(buffer); } System.out.println("拷贝完成"); } catch (Exception e) { e.printStackTrace(); }
注意,这里的输出流对象只能对文件内容进行覆盖,如果要进行附加,可以在实例化时使用重载的另一个构造器,将append
参数设置为true
。
字符流FileReader
和FileWriter
try (Reader fr = new FileReader("input/file/path"); Writer fw= new FileWriter("output/file/path")) { int len; char[] buffer = new char[10]; while ((len = fr.read(buffer)) !=-1){ fw.write(buffer, 0, len); } System.out.println("拷贝完成"); } catch (Exception e) { e.printStackTrace(); }
文件字符输出流在写文件时可以直接将字符串写入,这是针对字符型输出提供的接口。
注意,字符输出流写数据时会使用缓冲区,因此要让数据写到磁盘上的文件中,必须刷新流flush
(关闭流时会自动进行刷新操作,因此关闭流也行)。在缓冲区装满时会自动进行刷新操作。
缓冲流
缓冲流这样的流类是对原始流的包装,以提高在某些功能上的性能和便利性。
缓冲流是为了提高流读写数据的性能,在磁盘和程序读写数据的字节数组之间,设置一定大小的缓冲区(在内存中,大小默认为8KB)。
try (InputStream bis = new BufferedInputStream(new FileInputStream("input/file/path")); OutputStream bos = new BufferedOutputStream(new FileOutputStream("output/file/path"))) { // 在实例化时可以指定内部的缓冲区大小 int len; byte[] buffer = new byte[1024]; // 缓冲字节数组大小为1024KB while ((len = bis.read(buffer)) != -1) { bos.write(buffer, 0, len); } System.out.println("拷贝成功"); } catch (Exception e) { e.printStackTrace(); }
一般来说,把缓冲流和缓冲字节数组结合使用(如上面所示),数据读写的效率更高。
上面的示例使用的是字节缓冲流,字符缓冲流BufferedReader
和BufferedWriter
的使用大体一致。BufferedReader
提供了按行读取字符的接口public String readLine()
,在没有数据可读时会返回null
。BufferedWriter
提供了换行(输出新行)的接口public void newLine()
,在普通的字符输出流中,只能使用os.write("\r\n")
来输出新行。
转换流
编码、字符集的问题在字符流读写时会出现,如果代码编码和被读取的文本文件的编码不一致,会出现乱码的问题。
为了解决这个问题,可以使用字符输入/输出转换流InputStreamReader
和OutputStreamWriter
。它先获取原始字节流,再按照字符集编码转成字符流。
Reader isr = new InputStreamReader(new FileInputStream("input/file/path", "GBK"); BufferedReader br = new BufferedReader(isr);
打印流
打印流可以实现更方便高效的打印数据。
PrintStream ps = new PrintStream("print/file/path"); // 打印到文件中 PrintStream ps1 = new PrintStream(System.out); // 打印到控制台中
注意如果想要在文件后附加内容,需要在低级流对象实例化时指定append
参数,再使用该对象去实例化高级流对象,而高级流对象并不能直接指定该参数。
打印流可以实现标准输出的重定向。
System.out.println("打印到控制台"); System.setOut(ps); // 设置out重定向到文件中 System.out.println("打印到文件中");
数据流和序列化流
数据流DataInputStream
和DataOutputStream
将变量的类型和值一起读写到文件中。
序列化流ObjectInputStream
和ObjectOutputStream
和数据流类似,只不过它是将Java的对象序列化/反序列化到文件中。要想对自定义对象进行序列化/反序列化操作,必须让类实现Serializable
接口(这是一个标识接口,并没有任何抽象方法需要重写)。
IO框架
Java的框架一般是把类和接口等编译成字节码文件形式,压缩成一个.jar
文件发行出去。Apache提供了Commons-io框架,封装了一组相关的IO操作。
这里学习一下如何在idea中添加第三方框架。
- 下载框架并解压,找到需要导入的jar文件。
- 在idea中找到自己的module,新建一个目录命名为
lib
,在该目录下把需要导入的文件复制进去。 - 右键单机该jar文件,并选择
Add as Library
。 - 这样就可以在代码中导入包中的类了。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)