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

Java NIO使用及原理分析 (一)

最近由于工作关系要做一些Java方面的开发,其中最重要的一块就是Java NIO(New I/O),尽管很早以前了解过一些,但并没有认真去看过它的实现原理,也没有机会在工作中使用,这次也好重新研究一下,顺便写点东西,就当是自己学习 Java NIO的笔记了。本文为NIO使用及原理分析的第一篇,将会介绍NIO中几个重要的概念。

在Java1.4之前的I/O系统中,提供的都是面向流的I/O系统,系统一次一个字节地处理数据,一个输入流产生一个字节的数据,一个输出流消费一个字节的数据,面向流的I/O速度非常慢,而在Java 1.4中推出了NIO,这是一个面向块的I/O系统,系统以块的方式处理处理,每一个操作在一步中产生或者消费一个数据库,按块处理要比按字节处理数据快的多。

在NIO中有几个核心对象需要掌握:缓冲区(Buffer)、通道(Channel)、选择器(Selector)。

缓冲区Buffer

缓冲区实际上是一个容器对象,更直接的说,其实就是一个数组,在NIO库中,所有数据都是用缓冲区处理的。在读取数据时,它是直接读到缓冲区中的; 在写入数据时,它也是写入到缓冲区中的;任何时候访问 NIO 中的数据,都是将它放到缓冲区中。而在面向流I/O系统中,所有数据都是直接写入或者直接将数据读取到Stream对象中。

在NIO中,所有的缓冲区类型都继承于抽象类Buffer,最常用的就是ByteBuffer,对于Java中的基本类型,基本都有一个具体Buffer类型与之相对应,它们之间的继承关系如下图所示:

下面是一个简单的使用IntBuffer的例子:


    import java.nio.IntBuffer;  
      
    public class TestIntBuffer {  
        public static void main(String[] args) {  
            // 分配新的int缓冲区,参数为缓冲区容量  
            // 新缓冲区的当前位置将为零,其界限(限制位置)将为其容量。它将具有一个底层实现数组,其数组偏移量将为零。  
            IntBuffer buffer = IntBuffer.allocate(8);  
      
            for (int i = 0; i < buffer.capacity(); ++i) {  
                int j = 2 * (i + 1);  
                // 将给定整数写入此缓冲区的当前位置,当前位置递增  
                buffer.put(j);  
            }  
      
            // 重设此缓冲区,将限制设置为当前位置,然后将当前位置设置为0  
            buffer.flip();  
      
            // 查看在当前位置和限制位置之间是否有元素  
            while (buffer.hasRemaining()) {  
                // 读取此缓冲区当前位置的整数,然后当前位置递增  
                int j = buffer.get();  
                System.out.print(j + "  ");  
            }  
      
        }  
      
    }  
运行后可以看到:


在后面我们还会继续分析Buffer对象,以及它的几个重要的属性。

通道Channel

通道是一个对象,通过它可以读取和写入数据,当然了所有数据都通过Buffer对象来处理。我们永远不会将字节直接写入通道中,相反是将数据写入包含一个或者多个字节的缓冲区。同样不会直接从通道中读取字节,而是将数据从通道读入缓冲区,再从缓冲区获取这个字节。

在NIO中,提供了多种通道对象,而所有的通道对象都实现了Channel接口。它们之间的继承关系如下图所示:

使用NIO读取数据

在前面我们说过,任何时候读取数据,都不是直接从通道读取,而是从通道读取到缓冲区。所以使用NIO读取数据可以分为下面三个步骤:
1. 从FileInputStream获取Channel
2. 创建Buffer
3. 将数据从Channel读取到Buffer中

下面是一个简单的使用NIO从文件中读取数据的例子:

    import java.io.*;  
    import java.nio.*;  
    import java.nio.channels.*;  
      
    public class Program {  
        static public void main( String args[] ) throws Exception {  
            FileInputStream fin = new FileInputStream("<span style="font-family:FangSong_GB2312;">f</span>:\\<span style="font-family:FangSong_GB2312;">data</span>.txt");  
              
            // 获取通道  
            FileChannel fc = fin.getChannel();  
              
            // 创建缓冲区  
            ByteBuffer buffer = ByteBuffer.allocate(1024);  
              
            // 读取数据到缓冲区  
            fc.read(buffer);  
              
            buffer.flip();  
              
            while (buffer.remaining()>0) {  
                byte b = buffer.get();  
                System.out.print(((char)b));  
            }  
              
            fin.close();  
        }  
    }  

使用NIO写入数据

使用NIO写入数据与读取数据的过程类似,同样数据不是直接写入通道,而是写入缓冲区,可以分为下面三个步骤:
1. 从FileInputStream获取Channel
2. 创建Buffer
3. 将数据从Channel写入到Buffer中

下面是一个简单的使用NIO向文件中写入数据的例子:

    import java.io.*;  
    import java.nio.*;  
    import java.nio.channels.*;  
      
    public class Program {  
        static private final byte message[] = { 83, 111, 109, 101, 32,  
            98, 121, 116, 101, 115, 46 };  
      
        static public void main( String args[] ) throws Exception {  
            FileOutputStream fout = new FileOutputStream( "<span style="font-family:FangSong_GB2312;">f</span>:\\<span style="font-family:FangSong_GB2312;">data</span>.txt" );  
              
            FileChannel fc = fout.getChannel();  
              
            ByteBuffer buffer = ByteBuffer.allocate( 1024 );  
              
            for (int i=0; i<message.length; ++i) {  
                buffer.put( message[i] );  
            }  
              
            buffer.flip();  
              
            fc.write( buffer );  
              
            fout.close();  
        }  
    }  

本文介绍了Java NIO中三个核心概念中的两个,并且看了两个简单的示例,分别是使用NIO进行数据的读取和写入,Java NIO中最重要的一块Nonblocking I/O将在第三篇中进行分析,下篇将会介绍Buffer内部实现。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 使用ab进行压力测试的简单说明
  • Photoshop - 描边
  • js实现可兼容IE、FF、Chrome、Opera及Safari的音乐播放器
  • js面向对象:创建对象的几种方式
  • 正确理解ThreadLocal(转)
  • 软件工程课程总结
  • HDU 1166 敌兵布阵 (线段树)
  • gps相关
  • ibatis.net的一些映射文件语法
  • Channel SDK (渠道SDK) for Unity
  • OpenResty(Nginx)+Lua+GraphicsMagick实现缩略图功能
  • Python模块之urllib
  • MyEclipse8.6配置Maven
  • Nginx和PHP-FPM的启动/重启脚本 [转发]
  • Java知多少(88)列表和组合框
  • Angular2开发踩坑系列-生产环境编译
  • Apache的80端口被占用以及访问时报错403
  • Asm.js的简单介绍
  • C++类中的特殊成员函数
  • C学习-枚举(九)
  • ES学习笔记(10)--ES6中的函数和数组补漏
  • js操作时间(持续更新)
  • js对象的深浅拷贝
  • Selenium实战教程系列(二)---元素定位
  • Shadow DOM 内部构造及如何构建独立组件
  • SpiderData 2019年2月25日 DApp数据排行榜
  • 阿里云ubuntu14.04 Nginx反向代理Nodejs
  • -- 查询加强-- 使用如何where子句进行筛选,% _ like的使用
  • 前端性能优化--懒加载和预加载
  • 用 vue 组件自定义 v-model, 实现一个 Tab 组件。
  • UI设计初学者应该如何入门?
  • 不要一棍子打翻所有黑盒模型,其实可以让它们发挥作用 ...
  • ​猴子吃桃问题:每天都吃了前一天剩下的一半多一个。
  • ‌U盘闪一下就没了?‌如何有效恢复数据
  • # windows 安装 mysql 显示 no packages found 解决方法
  • #Datawhale AI夏令营第4期#多模态大模型复盘
  • #中国IT界的第一本漂流日记 传递IT正能量# 【分享得“IT漂友”勋章】
  • $(this) 和 this 关键字在 jQuery 中有何不同?
  • (4)STL算法之比较
  • (42)STM32——LCD显示屏实验笔记
  • (BAT向)Java岗常问高频面试汇总:MyBatis 微服务 Spring 分布式 MySQL等(1)
  • (C++)八皇后问题
  • (C++二叉树05) 合并二叉树 二叉搜索树中的搜索 验证二叉搜索树
  • (ZT) 理解系统底层的概念是多么重要(by趋势科技邹飞)
  • (八十八)VFL语言初步 - 实现布局
  • (附源码)springboot车辆管理系统 毕业设计 031034
  • (附源码)springboot家庭装修管理系统 毕业设计 613205
  • (附源码)springboot学生选课系统 毕业设计 612555
  • (离散数学)逻辑连接词
  • (三)Pytorch快速搭建卷积神经网络模型实现手写数字识别(代码+详细注解)
  • (十一)手动添加用户和文件的特殊权限
  • (原創) 如何將struct塞進vector? (C/C++) (STL)
  • (转)es进行聚合操作时提示Fielddata is disabled on text fields by default
  • (转载)在C#用WM_COPYDATA消息来实现两个进程之间传递数据
  • .L0CK3D来袭:如何保护您的数据免受致命攻击