Java核心技术【二十二】Java的I/O流处理:深入文件读写操作、缓冲流、序列化与NIO

Java的I/O流处理:深入文件读写操作、缓冲流、序列化

在Java编程中,I/O流是处理输入输出操作的基础,特别是在文件读写、网络通信等领域。本文将在前文的基础上,进一步探讨缓冲流、序列化以及NIO(New I/O)在文件读写操作中的应用和原理。

【创作】 不易,【点赞】 是情义,【关注】 是动力,【收藏】 是回忆
代码地址:https://gitee.com/code-in-java/csdn-blog.git

一、缓冲流(Buffering Streams)

缓冲流是对基本I/O流的增强,它通过在内存中创建一个缓冲区来减少对底层I/O设备的直接访问次数,从而提高读写效率。Java提供了BufferedInputStreamBufferedOutputStreamBufferedReaderBufferedWriter四种缓冲流。

1. 字节缓冲流

  • BufferedInputStream:用于读取数据,通过缓冲区减少磁盘I/O次数。
  • BufferedOutputStream:用于写入数据,数据首先写入缓冲区,当缓冲区满或调用**flush()**方法时,再将数据写入目标文件。

示例代码(字节缓冲流写入文件)

import java.io.BufferedOutputStream;  
import java.io.FileOutputStream;  
import java.io.IOException;  
  
public class BufferedWriteExample {  
    public static void main(String[] args) {  
        String data = "使用BufferedOutputStream写入数据";  
        try (BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("fileExample/buffered_output.txt"))) {  
            bos.write(data.getBytes());  
            bos.flush(); // 可选,因为try-with-resources会自动调用close(),而close()会先调用flush()  
            System.out.println("文件写入成功!");  
        } catch (IOException e) {  
            e.printStackTrace();  
        }  
    }  
}

2. 字符缓冲流

  • BufferedReader:用于高效读取文本文件,提供了readLine() 方法按行读取。
  • BufferedWriter:用于高效写入文本文件,提供了newLine() 方法用于写入行分隔符。

示例代码(字符缓冲流读取文件)

import java.io.BufferedReader;  
import java.io.FileReader;  
import java.io.IOException;  
  
public class BufferedReadExample {  
    public static void main(String[] args) {  
        try (BufferedReader br = new BufferedReader(new FileReader("fileExample/buffered_output.txt"))) {  
            String line;  
            while ((line = br.readLine()) != null) {  
                System.out.println(line);  
            }  
        } catch (IOException e) {  
            e.printStackTrace();  
        }  
    }  
}

运行结果:

使用BufferedOutputStream写入数据

二、序列化(Serialization)

序列化是将对象的状态信息转换为可以存储或传输的形式的过程。在Java中,这通常是通过实现 Serializable 接口并使用 ObjectOutputStreamObjectInputStream 类来完成的。

1. 序列化的关键作用

  • 持久化存储:序列化可以将对象的状态(即对象的数据成员)转换为字节序列,然后可以将这个字节序列保存到文件系统、数据库或其他持久化存储介质中。这样,即使Java虚拟机(JVM)关闭,对象的状态也不会丢失,可以在将来重新加载并恢复对象的状态。
  • 网络传输:在分布式系统或网络通信中,对象序列化允许将对象转换为字节流,便于通过网络传输。接收方收到字节流后,可以对其进行反序列化,重建原始对象。这对于远程方法调用(RMI)、Web服务、消息队列等场景非常有用。
  • 跨平台兼容性:序列化生成的字节流格式是跨平台的,这意味着在一台机器上序列化的对象可以在另一台不同操作系统或架构的机器上进行反序列化,只要后者支持相同的序列化协议。
  • 简化对象复制:有时候需要复制对象的实例,序列化提供了一种简便的方法来实现深拷贝,即创建一个与原对象具有相同状态的新对象,但两者在内存中是独立的实体。
  • 对象版本控制:通过序列化ID(serialVersionUID),可以管理类的不同版本,确保即使类的内部结构改变,仍然可以正确地反序列化旧版本的实例。
  • 实现特定功能: 某些Java框架或库可能依赖于序列化来实现特定的功能,例如缓存机制、配置管理等。

2. 序列化过程

  • 使对象所属的类实现 Serializable 接口。
  • 创建 ObjectOutputStream 实例,包装一个输出流(如 FileOutputStream )。
  • 调用 writeObject() 方法将对象序列化到输出流中。

3. 示例代码(序列化对象)

import java.io.FileOutputStream;  
import java.io.IOException;  
import java.io.ObjectOutputStream;  
import java.io.Serializable;  
  
public class SerializationExample implements Serializable {  
    private static final long serialVersionUID = 1L;  
    private String name;  
    private int age;  
    
    public static void main(String[] args) {  
        SerializationExample obj = new SerializationExample("张三", 30);  
        try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("fileExample/obj.ser"))) {  
            oos.writeObject(obj);  
            System.out.println("对象序列化成功!");  
            System.out.println();  
        } catch (IOException e) {  
            e.printStackTrace();  
        }  
    } 
  
    public SerializationExample(String name, int age) {
		super();
		this.name = name;
		this.age = age;
	}
	
	public String getName() {
		return name;
	}

	public int getAge() {
		return age;
	}
	public static long getSerialversionuid() {
		return serialVersionUID;
	} 
}

4. 代码运行结果

fileExample 路径下生成了一个文件 obj.ser 并保存了序列化的对象信息
在这里插入图片描述

三、反序列化

1. 反序列化过程

  • 创建 ObjectInputStream 实例,包装一个输入流(如 FileInputStream)。
  • 调用 readObject() 方法从输入流中读取对象,该方法返回 Object 类型,通常需要强制类型转换。

2. 示例代码(反序列化对象)

import java.io.FileInputStream;  
import java.io.IOException;  
import java.io.ObjectInputStream;  
  
public class DeserializationExample {  
    public static void main(String[] args) {  
    	//读取对象文件
        try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("fileExample/obj.ser"))) {  
            //读取对象后强制转换为 SerializationExample 类型
        	SerializationExample obj = (SerializationExample) ois.readObject();  
            //打印对象信息
        	System.out.println(obj.getName() + " " + obj.getAge());  
        } catch (IOException | ClassNotFoundException e) {  
            e.printStackTrace();  
        }  
    }  
}

3. 运行结果:

张三 30

四、NIO(New I/O)

NIO是Java 1.4及以后版本中引入的一种新的I/O处理方式,它提供了与标准I/O不同的I/O操作方式。NIO基于通道(Channel)和缓冲区(Buffer)的模型,使得I/O操作更加高效。

1. 通道(Channel)

通道是一个连接到I/O服务(如文件或套接字)的管道,用于读取和写入数据。常见的通道有FileChannelSocketChannel等。

2. 缓冲区(Buffer)

缓冲区是一个容器,它包含了一些要写入通道或者从通道中读出的数据。缓冲区实质上是一个数组,但提供了更多的操作,比如标记(mark)/重置(reset)、清空(clear)、反转(flip)等。

3. 选择器(Selector)

选择器允许单个线程处理多个通道,它是基于非阻塞I/O的。选择器会不断地轮询注册在其上的通道,如果某个通道处于就绪状态,则进行相应的I/O操作。

4. 示例代码(使用NIO写入文件)

import java.io.RandomAccessFile;  
import java.nio.ByteBuffer;  
import java.nio.channels.FileChannel;  
  
public class NIOWriteExample {  
    public static void main(String[] args) throws Exception {  
        String data = "使用NIO写入文件";  
        try (RandomAccessFile aFile = new RandomAccessFile("fileExample/nio_output.txt", "rw");  
             FileChannel inChannel = aFile.getChannel()) {  
            ByteBuffer buf = ByteBuffer.allocate(1024);  
            buf.clear();  
            buf.put(data.getBytes());  
            buf.flip();  
            while(buf.hasRemaining()){  
                inChannel.write(buf);  
            }  
            System.out.println("文件写入成功!");  
        }  
    }  
}

这段代码展示了如何使用Java NIO(New Input/Output)库中的FileChannelByteBuffer来写入文件。以下是详细解析:

1)创建 RandomAccessFile 对象

  • RandomAccessFile aFile = new
    RandomAccessFile(“fileExample/nio_output.txt”, “rw”);
  • 这行代码创建了一个 RandomAccessFile 对象 aFile,用于访问文件 “fileExample/nio_output.txt”。“rw” 模式表示文件将被用于读写。

2)获取 FileChannel

  • FileChannel inChannel = aFile.getChannel();
  • 通过 aFilegetChannel() 方法获取 FileChannel 对象 inChannelFileChannel 是一个用于文件IO操作的通道。

3)创建 ByteBuffer 并写入数据

  • ByteBuffer buf = ByteBuffer.allocate(1024);
  • 这行代码创建了一个容量为1024字节的 ByteBuffer 对象 buf
  • buf.clear(); 清除缓冲区,准备写入新数据。
  • buf.put(data.getBytes()); 将字符串 data 转换为字节后写入缓冲区。

4)切换缓冲区模式并写入文件

  • buf.flip(); 切换缓冲区的模式,从填充数据切换到准备释放数据。
  • while(buf.hasRemaining()){
    inChannel.write(buf);

    }循环检查缓冲区是否还有未写入的数据,如果有,则通过 inChannel.write(buf) 将数据写入文件。

总结,这段代码演示了如何使用 NIO 中的 FileChannelByteBuffer 将字符串数据写入文件。通过 RandomAccessFile 获取 FileChannel,然后使用 ByteBuffer 作为中介,将数据写入文件。

五、总结

Java的I/O流处理提供了丰富的API来支持各种输入输出操作。缓冲流通过减少底层I/O设备的直接访问次数来提高效率;序列化允许对象的状态被保存和传输;NIO则通过通道和缓冲区的模型进一步提高了I/O操作的性能。掌握这些技术对于进行高效的文件读写、网络通信等操作至关重要。

【创作】 不易,【点赞】 是情义,【关注】 是动力,【收藏】 是回忆,请接受我对您的 【谢意】

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/798058.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

从0开始的STM32HAL库学习2

外部中断(HAL库GPIO讲解) 今天我们会详细地学习STM32CubeMX配置外部中断,并且讲解HAL库的GPIO的各种函数。 准备工作: 1、STM32开发板(我的是STM32F103C8T6) 2、STM32CubeMx软件、 IDE: Keil软件 3、STM32F1xx/ST…

01- 收入数据集【Pytorch入门实战】

目录 一、机器学习基础 二、实战例子 1.数据集分析 2.实战训练 3.总结 三、参考资料 一、机器学习基础 为了解决这个问题,人们想到数据驱动方法,也就是让计算机从现有的大量的带标签图片电学习规律,一旦计算机学习到了其中的规律&…

sip协议栈简介

SIP协议栈简介 SIP协议栈流程 数据链路层:当SIP消息从网络中传输到达TCP/IP协议栈时,首先被接收到的是数据链路层的数据帧。数据链路层会对数据帧进行解封装,得到网络层的IP数据报。 网络层:网络层会对IP数据报进行解析&#xf…

1.27、基于径向基神经网络的曲线拟合(matlab)

1、基于径向基神经网络的曲线拟合简介及原理 1)原理简介 基于径向基神经网络(Radial Basis Function Neural Network, RBFNN)的曲线拟合是一种常用的非线性拟合方法,通过在输入空间中使用径向基函数对数据进行处理,实现对非线性关系的拟合。 RBFNN的基本原理是将输入空…

Java基础(十九):集合框架

目录 一、Java集合框架体系二、Collection接口及方法1、添加2、判断3、删除4、其它 三、Iterator(迭代器)接口1、Iterator接口2、迭代器的执行原理3、foreach循环 四、Collection子接口1:List1、List接口特点2、List接口方法3、List接口主要实现类:Array…

【Hive SQL 每日一题】在线峰值人数计算

文章目录 测试数据需求说明需求实现 测试数据 -- 创建 user_activity 表 DROP TABLE IF EXISTS user_activity ; CREATE TABLE user_activity (user_id STRING,activity_start TIMESTAMP,activity_end TIMESTAMP );-- 插入数据 INSERT INTO user_activity VALUES (user1, 2024…

算效最高的智算中心上线,天府智算为AI产业带来哪些启示?

四川简阳,地处川中、控扼巴峡,自古乃成渝、川鄂之间的交通重镇,素有“天府雄州”之美誉。 步入数字经济时代,“天府雄州”得天独厚的地理位置再次彰显出巨大的战略价值。简阳市成为成渝算力枢纽的天府数据中心集群关键布局点&…

element ui ts table重置排序

#日常# 今天带的实习生&#xff0c;在遇到开发过程中&#xff0c;遇到了element ui table 每次查询的时候都需要重置排序方式&#xff0c;而且多个排序是由前端排序。 <el-table :data"tableData" ref"restTable"> </<el-table> <script…

bi项目笔记

1.bi是什么 bi项目就是商业智能系统&#xff0c;也就是数据可视画、报表可视化系统&#xff0c;如下图的就是bi项目了 2.技术栈

深入了解 MySQL 的 EXPLAIN 命令

一、什么是 EXPLAIN 命令&#xff1f; EXPLAIN 命令用于显示 MySQL 如何执行某个 SQL 语句&#xff0c;尤其是 SELECT 语句。通过 EXPLAIN 命令&#xff0c;可以看到查询在实际执行前的执行计划&#xff0c;这对于优化查询性能至关重要。 二、EXPLAIN 的基本用法 要使用 EXP…

什么时候要用弗洛伊德算法

分析一下题目&#xff0c;我们看到数据量只有一百&#xff0c;这个时候我们就要注意是否是要用弗洛伊德算法&#xff0c;然后接着我们还需要枚举每一种情况&#xff0c;我们可以用到next_permutation这个方法 #include<bits/stdc.h> using namespace std;const int N 10…

matlab R2016b安装cplex12.6,测试时cplex出现出现内部错误的解决方法

问题场景 网上搜索matlabyalmipcplex的安装教程&#xff0c;跟着步骤操作即可&#xff0c;假如都安装好了&#xff0c;在matlab中测试安装是否成功&#xff0c;出现以下问题&#xff1a; 1、matlab中设置路径中添加了yalmip和cplex路径&#xff0c;在命令窗口中输入yalmiptest…

实现将Nginx的每个网站配置单独的nginx配置文件——每个网站单独管理

一、问题描述 Nginx默认地配置文件【nginx.conf】是包含了所有网站的配置内容,如果我们需要配置很多网站的话,就需要在默认的配置文件中给每个网站都添加一条server记录,这样下去nginx默认配置文件会变得很大,很难管理(比如有些网站不使用了,需要注销掉,也需要到该文件操…

openEuler 安装 podman 和 podman compose

在 openEuler 22.03 LTS SP4 中&#xff0c;你可以使用 dnf 包管理器来安装 Podman 和 Podman Compose。openEuler 默认使用 dnf 作为包管理器&#xff0c;所以这是安装软件的首选方式。 关于 openEuler 22.03 LTS SP4 下载地址&#xff1a; https://www.openeuler.org/zh/dow…

【接口自动化_06课_Pytest+Excel+Allure完整框架集成】

一、logging在接口自动化里的应用 1、设置日志的配置&#xff0c;并收集日志文件 日志的设置需要在pytest.ini文件里设置。这个里面尽量不要有中文 2、debug日志的打印 pytest.ini文件的开关一定得是true才能在控制台打印日志 import allure import pytest from P06_PytestFr…

Java中实现一维数组逆序交换的完整解决方案

引言 ❤❤点个关注吧~~编程梦想家&#xff08;大学生版&#xff09;-CSDN博客 在日常编程中&#xff0c;处理数组时经常会遇到需要逆序交换数组元素的情况。逆序交换即是将数组的第一个元素与最后一个元素交换&#xff0c;第二个元素与倒数第二个元素交换&#xff0c;依此类推…

HCIA学习笔记(6)-ACL+NAT

ACL&#xff1a;访问控制列表 访问控制-------在路由器的入或者出接口上&#xff0c;匹配流量&#xff0c;之后产生动作-----只有允许或拒绝 定义感兴趣流量------帮助其他策略去抓流量 匹配规则&#xff1a;至上而下&#xff0c;逐一匹配&#xff0c;上条匹配按照上条执行&…

JavaSE——集合框架二(4/6)-Map集合的遍历方式(键找值,键值对,Lambda)、Map集合案例(需求与分析,问题解决)

目录 Map集合的遍历方式 键找值 键值对 Lambda Map集合案例 需求与分析 问题解决 Map集合的遍历方式 键找值 先获取Map集合全部的键&#xff0c;再通过遍历键来找值。 键值对 把“键值对”看成一个整体进行遍历&#xff08;较为复杂&#xff09; Lambda JDK 1.8 开…

Cadence23学习笔记(二)

原理图设计界面中就可以直接新建PCB: 亲测&#xff1a;需要画完原理图&#xff0c;并且DRC通过之后才可以&#xff01; 放置完元器件之后要规定元件的Footprint &#xff0c;注意PCB封装名要和库文件中的名字对应&#xff1a; DRC按钮&#xff1a; 点击图标 N, 生成第一网表&…

MAVSDK动态库与静态库及mavsdk_server程序macOS平台编译与安装

1.克隆mavsdk: git clone https://github.com/mavlink/MAVSDK.git --recursive 2.编译静态库 cmake -Bbuild/default -H. -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=OFF 生成makefile 生成成功,开始编译 cmake --build build/default -j8 成功生成libmavsdk.a 开…