java——IO与NIO

news2024/10/6 10:27:28

文章目录

  • 1. 传统IO模型
    • 字节流
    • 字符流
  • 2. NIO模型

Java中的IO(输入输出)是用于在程序中读取和写入数据的一种机制。Java提供了两种不同的IO模型:传统的IO模型和NIO(New IO)模型。

1. 传统IO模型

在传统的IO模型中,输入和输出是通过字节流或字符流进行处理的。字节流是以8位字节为单位读写数据,而字符流则是以16位字符为单位读写数据。常见的字节流包括InputStream和OutputStream,而常见的字符流包括Reader和Writer。

另外,在传统的IO模型中,还有缓冲流,它们可以提高IO的效率。BufferedInputStream和BufferedOutputStream是字节流的缓冲流,而BufferedReader和BufferedWriter则是字符流的缓冲流。

传统IO模型的优点在于它简单易用,而缺点则是它的效率较低,特别是在处理大量数据时。

以下是一个简单的使用传统IO模型进行文件读写的Java代码示例:

import java.io.*;

public class TraditionalIOExample {

    public static void main(String[] args) {
        File inputFile = new File("input.txt");
        File outputFile = new File("output.txt");

        try {
            // 使用字节流读取文件
            FileInputStream fis = new FileInputStream(inputFile);
            // 使用字节流写入文件
            FileOutputStream fos = new FileOutputStream(outputFile);

            // 使用缓冲流提高效率
            BufferedInputStream bis = new BufferedInputStream(fis);
            BufferedOutputStream bos = new BufferedOutputStream(fos);

            // 读取数据并写入文件
            int len;
            byte[] buffer = new byte[1024];
            while ((len = bis.read(buffer)) != -1) {
                bos.write(buffer, 0, len);
            }

            // 关闭流
            bos.close();
            bis.close();
            fos.close();
            fis.close();

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

在这个例子中,我们首先创建了一个File对象,指定了输入文件和输出文件。然后使用FileInputStreamFileOutputStream来创建字节流,对文件进行读写操作。为了提高效率,我们还使用了缓冲流BufferedInputStreamBufferedOutputStream,将其包装在字节流之上。

接下来,在while循环中,我们不断从输入文件中读取数据,并将其写入到输出文件中。最后,我们关闭所有的流以释放资源。如果在读写过程中发生异常,我们就在catch块中捕获并打印异常信息。

这是一个简单的使用传统IO模型进行文件读写的例子,但实际上,传统IO模型还可以用于网络编程、对象序列化等方面。
在这里插入图片描述

字节流

字节流是Java IO中的一种流,它以字节为单位进行读写操作,用于处理二进制数据,如图像、音频等。字节流主要有两种类型:InputStream和OutputStream,分别用于从输入流中读取字节和向输出流中写入字节。

InputStream是所有字节输入流的超类,它定义了读取字节的基本方法,如read()、read(byte[] b)、read(byte[] b, int off, int len)等。其中,read()方法每次读取一个字节,返回一个整数表示实际读取的字节数,如果已经读到流的末尾,则返回-1。read(byte[] b)方法会尝试从输入流中读取b.length个字节,并将其存储在字节数组b中,返回值为实际读取的字节数。read(byte[] b, int off, int len)方法与read(byte[] b)类似,只不过指定了起始偏移量off和读取长度len。

OutputStream是所有字节输出流的超类,它定义了写入字节的基本方法,如write(int b)、write(byte[] b)、write(byte[] b, int off, int len)等。其中,write(int b)方法会将指定的字节写入输出流,write(byte[] b)方法会将字节数组b中的所有字节写入输出流,write(byte[] b, int off, int len)方法则只写入数组b中从偏移量off开始的len个字节。

除了基本的读写方法,字节流还提供了一些其他的常用方法。例如,InputStream中的available()方法返回可以从输入流中读取的估计字节数,mark(int readlimit)方法在输入流中标记当前位置,reset()方法将输入流重新定位到最后一次标记的位置,skip(long n)方法跳过指定的字节数等。而OutputStream中也有类似的方法,如flush()方法将输出流缓冲区的内容强制刷新到目标设备上,close()方法关闭流等。

下面是一个简单的示例代码,演示如何使用字节流进行文件读写操作:

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class ByteStreamDemo {
    public static void main(String[] args) throws IOException {
        // 从文件中读取数据,写入到另一个文件中
        FileInputStream fis = new FileInputStream("source.bin");
        FileOutputStream fos = new FileOutputStream("dest.bin");

        byte[] buffer = new byte[1024];
        int len;

        while ((len = fis.read(buffer)) != -1) {
            fos.write(buffer, 0, len);
        }

        fis.close();
        fos.close();
    }
}

上述代码通过创建FileInputStream和FileOutputStream来实现文件的读写操作,使用read()方法从源文件中读取字节,并使用write()方法将字节写入目标文件中。注意,在使用完流之后,需要及时调用close()方法关闭流。

字符流

字符流是Java IO中的一种流,它以字符为单位进行读写操作,用于处理文本数据,如文本文件、XML等。Java字符流主要有两种类型:Reader和Writer,分别用于从输入流中读取字符和向输出流中写入字符。

Reader是所有字符输入流的超类,它定义了读取字符的基本方法,如read()、read(char[] cbuf)、read(char[] cbuf, int off, int len)等。其中,read()方法每次读取一个字符,返回一个整数表示实际读取的字符数,如果已经读到末尾,则返回-1;read(char[] cbuf)方法会尝试从输入流中读取cbuf.length个字符,并将其存储在字符数组cbuf中,返回值为实际读取的字符数;read(char[] cbuf, int off, int len)方法与read(char[] cbuf)类似,只不过指定了起始偏移量off和读取长度len。

Writer是所有字符输出流的超类,它定义了写入字符的基本方法,如write(int c)、write(char[] cbuf)、write(String str)等。其中,write(int c)方法会将指定的字符写入输出流;write(char[] cbuf)方法会将字符数组cbuf中的所有字符写入输出流;write(String str)方法会将字符串str中的所有字符写入输出流。

除了基本的读写方法,字符流也提供了一些其他的常用方法。例如,Reader中的skip(long n)方法跳过n个字符,mark(int readAheadLimit)方法在输入流中标记当前位置,reset()方法将输入流重新定位到最后一次标记的位置等;而Writer中的flush()方法将输出流缓冲区的内容强制刷新到目标设备上,close()方法关闭流等。

下面是一个简单的示例代码,演示如何使用字符流进行文件读写操作:

import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

public class CharacterStreamDemo {
    public static void main(String[] args) throws IOException {
        // 从文件中读取数据,写入到另一个文件中
        FileReader fr = new FileReader("source.txt");
        FileWriter fw = new FileWriter("dest.txt");

        char[] buffer = new char[1024];
        int len;

        while ((len = fr.read(buffer)) != -1) {
            fw.write(buffer, 0, len);
        }

        fr.close();
        fw.close();
    }
}

上述代码通过创建FileReader和FileWriter来实现文件的读写操作,使用read()方法从源文件中读取字符,并使用write()方法将字符写入目标文件中。注意,在使用完流之后,需要及时调用close()方法关闭流。

2. NIO模型

NIO是Java 1.4引入的新IO模型,它的目标是提高IO的效率,特别是在处理大量数据时。NIO的设计中引入了三个重要的概念:通道、缓冲区和选择器。

通道是NIO中的抽象概念,它类似于传统IO模型中的流。但是,通道可以同时进行读写操作,并且可以使用选择器来实现多路复用,从而提高效率。

缓冲区是NIO中的另一个重要概念,它用于存储读取或写入的数据。与传统IO模型不同的是,NIO中的缓冲区可以直接与通道交互,从而避免了频繁地进行字节或字符的拷贝操作,提高了效率。

选择器是NIO中的另一个重要概念,它可以监听多个通道上的事件并在有事件发生时及时地处理它们。这样,一个线程就可以同时处理多个通道上的IO操作,从而避免了线程阻塞等问题,提高了系统的效率和可扩展性。

下面是一个基于NIO模型的简单示例代码:

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;

public class NioServer {
    private Selector selector;

    public void init() throws IOException {
        // 创建一个选择器
        selector = Selector.open();

        // 创建一个ServerSocketChannel并绑定到指定端口
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        serverSocketChannel.bind(new InetSocketAddress(8888));
        serverSocketChannel.configureBlocking(false);

        // 将ServerSocketChannel注册到选择器上,监听ACCEPT事件
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
    }

    public void start() throws IOException {
        while (true) {
            // 阻塞等待就绪的Channel
            selector.select();

            // 获取所有已就绪的Channel
            Iterator<SelectionKey> keyIterator = selector.selectedKeys().iterator();

            while (keyIterator.hasNext()) {
                SelectionKey key = keyIterator.next();

                if (key.isAcceptable()) {
                    // 处理连接请求
                    ServerSocketChannel serverSocketChannel = (ServerSocketChannel) key.channel();
                    SocketChannel socketChannel = serverSocketChannel.accept();
                    socketChannel.configureBlocking(false);
                    System.out.println("接受新的连接:" + socketChannel.getRemoteAddress());

                    // 将新连接的SocketChannel注册到选择器上,监听READ事件
                    socketChannel.register(selector, SelectionKey.OP_READ);
                } else if (key.isReadable()) {
                    // 处理读取数据
                    SocketChannel socketChannel = (SocketChannel) key.channel();
                    ByteBuffer buffer = ByteBuffer.allocate(1024);
                    int readBytes = socketChannel.read(buffer);

                    if (readBytes > 0) {
                        buffer.flip();
                        byte[] bytes = new byte[buffer.remaining()];
                        buffer.get(bytes);
                        String content = new String(bytes, "UTF-8");
                        System.out.println("接收到客户端消息:" + content);

                        // 回写数据
                        buffer.clear();
                        buffer.put("Hello client!".getBytes());
                        buffer.flip();
                        socketChannel.write(buffer);
                    } else if (readBytes < 0) {
                        // 连接关闭
                        key.cancel();
                        socketChannel.close();
                    }
                }

                // 移除当前已处理的事件
                keyIterator.remove();
            }
        }
    }

    public static void main(String[] args) throws IOException {
        NioServer server = new NioServer();
        server.init();
        server.start();
    }
}

上述代码中,首先创建了一个选择器(Selector)对象。然后创建了一个ServerSocketChannel并将其注册到选择器上,监听ACCEPT事件。接着进入主循环,调用select()方法阻塞等待就绪的Channel,然后使用selectedKeys()方法获取所有已就绪的Channel,遍历每个已就绪的Channel,根据其状态进行相应的处理。如果是新连接请求,就接受连接并将新的SocketChannel注册到选择器上,监听READ事件;如果是数据读取请求,就读取数据并回写数据。

需要注意的是,在NIO模型中,数据的读写操作是通过缓冲区(Buffer)对象完成的,所以需要在代码中使用ByteBuffer等缓冲区对象来处理数据。另外,NIO模型还需要特别注意内存泄漏的问题,因为它很容易发生,需要及时释放资源和取消注册。

总的来说,NIO比传统的IO模型更适合处理大量数据时的IO操作,并且具有更好的效率和可扩展性。但是,NIO的学习曲线相对较陡峭,需要掌握一定的底层知识和技能。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

WPF本地化/国际化,多语言切换

之前写过winformwinform使用本地化&#xff0c;中英文切换_winform 中英文切换_故里2130的博客-CSDN博客 基本的技术差不多&#xff0c;但是后来又发现了一个ResXManager工具&#xff0c;可以更好方便快捷的使用。 首先下载&#xff0c;网络不好的话&#xff0c;去官网下载&a…

01背包简介

01背包问题&#xff08;0/1 Knapsack problem&#xff09;是一个经典的动态规划问题&#xff0c;它描述了在给定容量限制的情况下&#xff0c;如何选择一组物品放入背包&#xff0c;以使得物品的总价值最大化。 问题描述&#xff1a; 假设有一个背包&#xff0c;其容量为C。现…

VulnHub项目:Fawkes

1、靶机地址 HarryPotter: Fawkes ~ VulnHub 该篇为哈利波特死亡圣器系列最终部&#xff0c;也是最难的一个靶机&#xff0c;难度真的是逐步提升&#xff01;&#xff01;&#xff01; 2、渗透过程 确认靶机IP&#xff0c;kali IP&#xff0c;探测靶机开放端口 详细的扫描…

ICLR 23 | 工业视觉小样本异常检测最新网络:Graphcore

来源&#xff1a;投稿 作者&#xff1a;橡皮 编辑&#xff1a;学姐 论文链接&#xff1a;https://openreview.net/pdf?idxzmqxHdZAwO 论文代码&#xff1a;尚未开源 1.背景 随着人工智能中深度视觉检测技术的快速发展&#xff0c;检测工业产品表面的异常/缺陷受到了前所未有…

scratch lenet(11): C语言实现 squashing function

文章目录 1. 目的2. Sigmoidal Function2.1 S2 用到 Sigmoidal Function2.2 Sigmoidal Function 的定义 3. Squashing Function3.1 改用 Sigmoid Suahsing function 术语3.2 具体到 hyperlolic tangent 这一 squahsing function 4. Squahsing function 的实现References 1. 目的…

设计模式之观察者模式笔记

设计模式之观察者模式笔记 说明Observer(观察者)目录观察者模式示例类图抽象主题角色类抽象观察者类具体主题角色类具体的观察者角色类测试类 说明 记录下学习设计模式-观察者模式的写法。JDK使用版本为1.8版本。 Observer(观察者) 意图:定义对象间的一种一对多的依赖关系&a…

Gradle构建系统macOS安装与使用

1.打开gradle.org并点击安装 2.先决条件 ,确认安装JDK1.8或者更高版本已安装 在终端输入brew install gradle进行安装 安装成功如下: 查看安装版本号gradle -v 使用gradle 1.创建目录demo并进入该目录 mkdir demo cd demo 2.gradle init 使用Gradle开始构建 输入2开始构建应…

DevOps系列文章之 docker插件实现多实例部署(IDEA插件)

1. Docker的安装以及开启远程访问 1.1 安装 # 检查虚拟机内核版本&#xff0c;必须是3.10及以上 uname -r # 安装docker yum install docker # 输入y确认安装 # 启动docker systemctl start docker # 查看docker版本 docker -v # 开机启动docker systemctl enable docker # 停…

Golang学习日志 ━━ gin-vue-admin换机重新配置的记录,很愚蠢,很傻瓜,很机械...自己使用

最近一直在弄AI&#xff0c;没时间搞gva&#xff0c;所以有点忘记了&#xff0c;代码升级管它呢&#xff0c;全部重来一遍~ 一、备份保存 根据经验和个人喜好&#xff0c;我特别不喜欢在框架下把一个应用分散在module、api、service等等目录下&#xff0c;这种目录分配方案将把…

图上作业法

目录 交通示意图的表示方法 图上作业法 &#xff08;1&#xff09;对流 &#xff08;2&#xff09;迂回 物资调运问题的图上作业法 交通路线不成圈 交通路线成圈 交通示意图的表示方法 交通示意图是用来表明收发点的大致位置、收发量、交通路线长度的图形。 图形表示…

java mail发送、接收邮件

java mail接收邮件 1、引入java mail依赖 <dependency><groupId>org.eclipse.angus</groupId><artifactId>angus-mail</artifactId><version>2.0.2</version> </dependency>2、编写代码 注意&#xff1a;下述代码中的服务器…

从BNO055传感器获取IMU数据-2

在前面的文章 从BNO055传感器获取IMU数据-1 中介绍了BNO055传感器&#xff0c;今天继续讲解应用示例。 传感器与Arduino接口 我从某宝购买了固定在带有支持组件的开发板上的 BNO055 传感器。从 Digi-Key 或贸泽购买 BNO055 并将其焊接到 7.54.4mm 28 引脚 LGA 至 DIP 转换器上…

Groovy基础

Groovy基础 学Groovy有什么用&#xff1f;&#xff1f;&#xff1f;一、Groovy简介二、Mac安装Groovy1、使用homebrew安装或官网下载2、配置环境变量3、重新加载环境变量 二、Groov基本语法三、更多特性和扩展四、Groovy简单使用1、Groovy中的字符串及三大语句结构2、Groovy类与…

1带你入门MATLAB图像处理图像类型转换(附matlab程序)

1.简述 学习目标&#xff1a; 图像类型的转换 常用图像格式 图像格式&#xff1a;是存储图像采用的文件格式。不同的操作系统、不同的图像处理软件&#xff0c;所支持的图像格式都有可能不同。 在实际应用中经常会遇到的图像格式有&#xff1a;BMP、GIF、TIFF、PCX、JPEG、P…

FFmpeg5.0源码阅读——avformat_open_input

摘要&#xff1a;本文主要描述了FFmpeg中用于打开文件接口avformat_open_input的具体调用流程&#xff0c;详细描述了该接口被调用时所作的具体工作。   关键字&#xff1a;ffmpeg、avformat_open_input   注意&#xff1a;读者需要了解FFmpeg的基本使用流程&#xff0c;以…

力扣动态规划专题(五)子序列问题 不连续子序列与连续子序列 步骤及C++实现

文章目录 300.最长递增子序列674.最长连续递增子序列动态规划贪心算法 718. 最长重复子数组二维dp数组一维dp数组 1143.最长公共子序列1035.不相交的线53. 最大子序和动态规划贪心算法 300.最长递增子序列 步骤 确定dp数组以及下标的含义 dp[i]&#xff1a;i之前&#xff08;包…

【数据结构】单链表 创建 插入 删除 查找 完整代码

3.1 单链表 3.1.1 定义 注&#xff1a; 元素离散的分布在存储空间中&#xff0c;所以单链表是非随机存取的存储结构。 即不能直接找到表中某个特定的结点&#xff0c;需要从表头开始遍历&#xff0c;依次查找。 定义的代码 typedef struct LNode {ElemType data;//每个节点存放…

第三章 处理机调度与死锁

目录 一、调度的概念、层次 2.1 调度的基本概念 2.2 调度的三个层次 2.2.1 高级调度 2.2.2 低级调度 2.2.3 中级调度 2.2.3.1 进程的挂起态 2.2.4 三层调度的联系、对比 二、进程调度的时机、切换与过程、方式 2.1 进程调度的时机 2.2 进程调度的方式 2.2.1 非抢占…

计网复习题

一、单项选择题 OSI参考模型的物理层负责&#xff08;&#xff09;。 A&#xff0e;格式化报文 B&#xff0e;为数据选择通过网络的路由(网络层) C&#xff0e;定义连接到介质的特性 D&#xff0e;提供远程文件访问能力(应用层) 下列选项中&#xff0c;不属于网络体系结构中所…