当前位置: 首页 > news >正文

文件操作和IO(下)

       

目录

字节流

流对象的两种关闭方式

InputStream

OutputStream

字符流

Reader

Writer 


        在上一篇文章中,主要介绍了在Java中如何进行文件系统操作,具体见博客: 文件操作和IO(上)在本篇中主要介绍如何对文件内容进行操作。

        对于文件内容的操作,主要使用流对象来进行,具体可以分为两个大类:字节流和字符流,下面将详细展开两种方式的具体细节和使用示例。

字节流

        字节流主要是针对二进制文件进行处理,其读写数据的基本单位是字节,主要包括InputStream 和 OutputStream 两个类。

流对象的两种关闭方式

        在创建了 InputStream 或者 OutputStream 对象且执行完操作后,为了避免资源泄露,我们需要显式地关闭这些流对象。关闭流对象的操作应该始终在完成 I/O 操作后进行,以确保流所占用的资源(如内存、文件句柄等)能够得到及时释放。在 Java 中,关闭流的操作有常见的两种方式:

· 使用 Finally 块来关闭流

 public static void main(String[] args) {InputStream inputStream = null;try {// 此处隐含了一个操作,打开文件inputStream = new FileInputStream("./test.txt");}catch (IOException e) {e.printStackTrace();} finally {try {inputStream.close();} catch (IOException e) {throw new RuntimeException(e);}}}

        这种写法虽然可以保证严谨性,但其写法较为麻烦,因此我们通常使用另一种简单的方式来进行关闭,具体如下所示:

· 使用 try-with-resources 语句 

    public static void main(String[] args) {try(InputStream inputStream = new FileInputStream("./test.txt")) {} catch (IOException e) {e.printStackTrace();}}

        在上述代码中,try() 中创建的资源可以是多个,使用 “;” 来进行分隔,try 的 {} 中的代码执行完毕后,最后都会自动执行 close 方法,因为 InputStream 这个抽象类实现了 Closeable 接口。

InputStream

        在使用 InputStream 进行读取文件内容时,通常使用该抽象类的子类 FileInputStream 来进行操作。在使用其进行文件读取时,有三种读 read 方法,具体如下所示:        第一个 read 方法表示一次读取一个字节,返回值为该字节的内容;第二个 read 方法则是一次读取多个字节,它需要我们首先定义一个 buffer 数组,并将该数组传入 read 方法,buffer 数组在这里充当“输出型参数”;第三个 read 方法是在第二个方法的基础上扩展的,它允许我们指定一个字节数组的特定区间(即 [off, off + len)),并将数据填充到该区间中,而不是整个数组。

        以下为分别使用这三种方法进行文件内容读取的具体示例:

/*** 一次读取一个字节* @param args*/public static void main(String[] args) {try(InputStream inputStream = new FileInputStream("./test.txt")) {while (true) {// 一次读一个字节int b = inputStream.read();if (b == -1) {// 读取完毕break;}// 表示字节,更习惯使用 16 进制来打印显示System.out.printf("0x%x\n", b);}} catch (IOException e) {e.printStackTrace();}}
/*** 使用 buffer 数组* @param args*/public static void main(String[] args) {try (InputStream inputStream = new FileInputStream("./test.txt")) {while (true) {byte[] buffer = new byte[1024];// 将硬盘中读到的对应数据,填充到 buffer 内存的字节数组中,尽可能填满 (一次 IO 尽可能填满)// 此处将 buffer 当成了“输出型参数”// n 返回值表示 read 操作,实际读取到多少个字节。int n = inputStream.read(buffer);if (n == -1) {break;}for (int i = 0; i < n; i++) {System.out.printf("0x%x\n", buffer[i]);}}} catch (IOException e) {e.printStackTrace();}}/*** 使用 buffer 数组限制范围读取* @param args*/public static void main(String[] args) {try (InputStream inputStream = new FileInputStream("./test.txt")) {while (true) {byte[] buffer = new byte[1024];// 将硬盘中读到的对应数据,填充到 buffer 内存的字节数组中,尽可能填满 (一次 IO 尽可能填满)// 此处将 buffer 当成了“输出型参数”// n 返回值表示 read 操作,实际读取到多少个字节。int n = inputStream.read(buffer, 0, 256);if (n == -1) {break;}for (int i = 0; i < n; i++) {System.out.printf("0x%x\n", buffer[i]);}}} catch (IOException e) {e.printStackTrace();}}

OutputStream

        在使用 OutputStream 进行填写文件内容时,通常使用该抽象类的子类 FileOutputStream 来进行操作。在使用其进行文件内容填写时,与 InputStream 类似,有三种写 write 方法,三种方法的不同之处也与 read 方法类似,其具体使用示例如下所示:

    /*** 一次写一个字节* @param args*/public static void main1(String[] args) {// true 表示追加写try (OutputStream outputStream = new FileOutputStream("./test.txt", true)) {// 此处的写操作,会把之前的内容清空(只要使用 OutputStream 打开文件,内容就没了),再进行写操作outputStream.write(0xe4);outputStream.write(0xbd);outputStream.write(0xa0);outputStream.write(0xe5);outputStream.write(0xa5);outputStream.write(0xbd);} catch (IOException e) {e.printStackTrace();}}/*** 一次写多个字节* @param args*/public static void main(String[] args) {// true 表示追加写try (OutputStream outputStream = new FileOutputStream("./test.txt", true)) {// 此处的写操作,会把之前的内容清空(只要使用 OutputStream 打开文件,内容就没了),再进行写操作byte[] buffer = new byte[] { (byte)0xe4, (byte)0xbd, (byte)0xa0, (byte)0xe5, (byte)0xa5, (byte)0xbd};outputStream.write(buffer);} catch (IOException e) {e.printStackTrace();}}

        在下面这行代码中,在 new FileOutputStream 对象时除了传入文件路径外,还传入了 true。如果我们不传入 true,在进行写操作时,会将之前文件中的内容清空,再进行写操作,也就是说只要使用 outputStream 打开文件,文件中的内容就会清空,而传入 true 后,也就意味着将其指定为“追加写”的方式,其在保留源文件中内容的基础上,在其后面写入新的内容。

try (OutputStream outputStream = new FileOutputStream("./test.txt", true)) {}

字符流

        InputStream 和OutputStream 读写数据是按照字节来进行操作的,当要读取字符(中文)时,需要我们手动的来区分哪几个字节是一个字符,再确保把这几个字节作为整体来进行写入,为了更方便的处理字符,Java引入了字符流。其包括 Reader 和 Writer两个类。

        对于字符流的关闭方式与字节流一样,常用的方法包括使用 Finally 块来关闭流和使用 try-with-resources 语句两种方式,通常我们使用后者。

Reader

        在使用 Reader进行读取文件内容时,通常使用该抽象类的子类 FileReader 来进行操作。在使用其进行文件读取时,有四种读 read 方法,具体如下所示:

        第一个 read 方法表示一次读取一个字符,返回值为该字符的内容;第二个 read 方法则是一次读取多个字符,它需要我们首先定义一个 buffer 数组,并将该数组传入 read 方法,buffer 数组在这里充当“输出型参数”,返回值表示实际读到的字符个数;第三个 read 方法也是一次读取多个字符,其与第二种方法的不同之处在于,第二种方法使用 buffer 数组,而该方法是使用 CharBuffer,它是一个可以自动扩展的缓冲区,因此它可以容纳更多的数据;第四个 read 方法是在第二个方法的基础上扩展的,它允许我们指定一个字符数组的特定区间(即 [off, off + len)),并将数据填充到该区间中,而不是整个数组。 

        常用的使用方式如下所示:

/*** reader 一次读取一个字符* @param args*/public static void main(String[] args) {try (Reader reader = new FileReader("./test.txt")) {while (true) {int c = reader.read();if (c == -1) {break;}char ch = (char)c;System.out.println(ch);}} catch (IOException e) {e.printStackTrace();}}/*** 一次读取多个字符* @param args*/public static void main(String[] args) {try (Reader reader = new FileReader("./test.txt")) {char[] buffer = new char[1024];int n = reader.read(buffer);System.out.println(n);for (int i = 0; i < n; i++) {System.out.println(buffer[i]);}} catch (IOException e) {e.printStackTrace();}}/*** 一次读取多个字符(指定 buffer 数组范围)* @param args*/public static void main(String[] args) {try (Reader reader = new FileReader("./test.txt")) {char[] buffer = new char[1024];int n = reader.read(buffer, 0, 256);System.out.println(n);for (int i = 0; i < n; i++) {System.out.println(buffer[i]);}} catch (IOException e) {e.printStackTrace();}}

Writer 

        在使用 Reader进行写入文件内容时,通常使用该抽象类的子类 FileWriter 来进行操作。在使用其进行文件写入时,有五种写入 write方法,具体如下所示:

        第一种 write 表示一次可以写入一个字符串,第二种 write 表示一次写入一个字符;第三种 write 表示一次写入一个 buffer 数组的字符;第四种和第五种,都是根据第二种和第三种方法限定了其一次写入的范围。

        其常用的使用方式如下所示:

    /*** 一次写入一个字符* @param args*/public static void main(String[] args) {try (Writer writer = new FileWriter("./test.txt", true)) {writer.write('你');} catch (IOException e) {e.printStackTrace();}}    /*** 一次写入多个字符* @param args*/public static void main(String[] args) {try (Writer writer = new FileWriter("./test.txt", true)) {char[] buffer = {'你', '好', '呀'};writer.write(buffer);} catch (IOException e) {e.printStackTrace();}}/*** 一次写入一个字符串* @param args*/public static void main(String[] args) {try (Writer writer = new FileWriter("./test.txt", true)) {writer.write("你好世界");} catch (IOException e) {e.printStackTrace();}}

http://www.xdnf.cn/news/339085.html

相关文章:

  • 基础编程题目集 6-8 简单阶乘计算
  • 【Rust错误处理】Rust错误处理机制详解与应用实战
  • Go:简洁高效,构建现代应用的利器
  • 按摩椅的机芯类型和材质
  • 数字化驱动下的智慧物流与零售创新:全流程无人仓与定制开发开源AI智能名片S2B2C商城小程序的协同实践
  • 大模型(LLMs)推理面
  • android-ndk开发(10): use of undeclared identifier ‘pthread_getname_np‘
  • python读写json文件
  • 手撕基于AMQP协议的简易消息队列-7(客户端模块的编写)
  • 数字孪生技术中端渲染与流渲染的架构对比
  • linux中的常用命令(一)
  • STM32智能刷卡消费系统(uC/OS-III)
  • commonmark.js 源码阅读(一) - Block Parser
  • ComfyUI 学习笔记,案例 6 :FLUX 模型文生图
  • 【Linux系列】目录大小查看
  • 【Python 日期和时间】
  • 【redis】集群模式
  • Windows命令行软件管理器:Chocolatey
  • 多级路由器如何避免IP冲突
  • 使用JAVA对接Deepseek API实现首次访问和提问
  • Linux网络编程day7 线程池
  • 因子分析——数学原理及R语言代码
  • flinksql bug : Max aggregate function does not support type: CHAR
  • 援外培训项目冈比亚数字政府能力建设研修班莅临麒麟信安参观考察
  • Ubuntu每次开机IP都是127.0.0.1
  • Debian系统详解
  • linux命令行与shell脚本大全——学习笔记(9-10章)
  • ABP vNext + Dapr 实现云原生微服务治理
  • Sass @import rules are deprecated and will be removed in Dart Sass 3.0.0.
  • C++类和对象:构造函数、析构函数、拷贝构造函数