NIO简介

JAVA NIO是在JDK1.4中引入的,因此它是一个很古老的特性了。与NIO相对应的我们称之为BIO(阻塞IO)。NIO相比于BIO的区别有很多,比如BIO是面向流的,而NIO是面向块的,但最根本的区别在于是否阻塞,BIO是阻塞的,而NIO是非阻塞的。

阻塞是指线程处理过程中,如果需要IO,则线程一直等待,直到拿到需要的数据继续往下执行。非阻塞则是线程发出IO指令后,不会立刻得到结果,也不会阻塞等待,它让出CPU让其他线程执行。一旦IO指令有了结果后,以回调或监听等方式通知调用线程继续执行后续处理。无疑,NIO对整个系统性能来讲更友好,效率更好。

关于Buffer

谈到NIO,就不能不提它的一个重要部件Buffer,顾名思义,buffer就是缓冲区,它是对IO数据进行临时存储的内存区域。使用缓冲区可将多次读写数据暂存于内存,等一个合适的时机再做实际的IO操作(比如通过网络发包、写入磁盘等),从而减少实际的物理读写次数。

JAVA NIO 的Buffer是一个抽象类,它的一个及其重要的子类就是ByteBuffer,也是一个抽象类。ByteBuffer有很多实现,见下图。

ByteBuffer类图结构

关于Buffer在JDK中是一个庞大的实现,各种特性的buffer适应于各种应用场景,本篇我们仅就ByteBuffer做一些分析介绍。

HeapByteBuffer:它分配在JVM的堆内存上,底层数据结构是一个数组。

DirectByteBuffer:它与HeapByteBuffer不一样,它是在JVM之外开辟了一块内存区域,位于操作系统的内存中,JVM里维护一个引用address指向这片内存区域。这样的优势是和IO设备交互时,性能更优。因为外设不能直接和JVM内存交换数据,而是需要把JVM内存数据和系统内存进行一次交换,外设只和系统内存进行交换。使用DirectByteBuffer,则可以省去这一步,实现所谓的zero copy (零拷贝)。

ByteBuffer的用法

属性

所有Buffer都有4个属性:capacity、limit、position、mark,并遵循mark <= position <= limit <= capacity的原则。这四个属性的含义解释如下:

方法

实例化方法

如前所属Buffer类是一个抽象类。它的直接子类(如ByteBuffer等)也是抽象类,它们不能被直接实例化。我们要创建Buffer对象可以使用它自带的一些特定方法来实现。比如ByteBuffer类提供了4个静态工厂方法供我们来得到ByteBuffer的实例。

一些常用方法

示例代码

我就ByteBuffer结合FileChannel写了一些简单的示例代码,没有用到很多的ByteBuffer方法的特性,有些简陋,仅做抛砖引玉之用。

下面这行代码是将字符串写入byteBuffer中,此时,byteBuffer为写模式。

ByteBuffer byteBuffer = ByteBuffer.wrap(content.getBytes());

代码一

下面的代码我使用ByteBuffer实现一个字符串写入文件的功能。

ByteBuffer byteBuffer = ByteBuffer.wrap(content.getBytes());

上面这行代码是将字符串写入byteBuffer中,实例化方法用的是wrap(),此时,byteBuffer为写模式。

ByteBuffer byteBuffer01 = ByteBuffer.allocate(content.getBytes().length);

byteBuffer01.put(content.getBytes());

除了warp方法可以将内容放入缓冲区外,也可以使用put()方法将内容放入ByteBuffer中,像上面这样。

byteBuffer.flip();

上面这行代码是将写模式切换为读模式,因为后续需要读取byteBuffer的内容写入文件。

public static void writeContentToFile(String content,String filePath){

//创建一个buffer,按实际内容分配buffer大小

ByteBuffer byteBuffer = ByteBuffer.wrap(content.getBytes());

// ByteBuffer byteBuffer01 = ByteBuffer.allocate(content.getBytes().length);

// byteBuffer01.put(content.getBytes());

//反转buffer的模式为读模式

byteBuffer.flip();

try(FileOutputStream fo = new FileOutputStream(filePath);

FileChannel channel = fo.getChannel()) {

while(byteBuffer.hasRemaining()) {

channel.write(byteBuffer);

}

}catch (Exception e){

e.printStackTrace();

}

}

代码二

下面的代码是使用FileChannel将内容从文件读取到ByteBuffer中,然后再从ByteBuffer把数据写入另外一个文件,从而实现文件复制。

ByteBuffer byteBuffer = ByteBuffer.allocate(512);

上面这行代码是ByteBuffer的又一个实例化方法,直接分配大小为512的byte数组作为缓冲区。

public static void readContentToAnotherFile(String sourceFilePath,String targetFilePath){

ByteBuffer byteBuffer = ByteBuffer.allocate(512);

try(FileInputStream inputStream = new FileInputStream(sourceFilePath);

FileChannel readChannel = inputStream.getChannel();

FileOutputStream fo = new FileOutputStream(targetFilePath);

FileChannel writeChannel = fo.getChannel()) {

//读取文件到buffer

readChannel.read(byteBuffer);

byteBuffer.put("\n".getBytes());

byteBuffer.put("copy successful".getBytes());

//反转buffer的模式为读模式

byteBuffer.flip();

while(byteBuffer.hasRemaining()) {

writeChannel.write(byteBuffer);

}

}catch (Exception e){

e.printStackTrace();

}

}

本代码只是示例代码,对于超过512的文件拷贝并不适用,需要自己完善修改。

代码三

本示例严格来讲,算不上ByteBuffer的示例代码,只是由于前面两个例子都是讲的文件操作相关,且FileChannel也是一个常用的NIO类,索性就一并写在这,供大家交流。下面这个例子也是一个文件拷贝的例子,使用FileChannel的transferFrom或transferTo方法,寥寥几行代码,轻松实现文件拷贝。

public static void copyFile(String sourceFilePath,String targetFilePath){

try(FileChannel inputChannel = new FileInputStream(sourceFilePath).getChannel();

FileChannel outputChannel = new FileOutputStream(targetFilePath).getChannel();) {

//两种写法都是可以的,只是主动和被动方的表现形式不一样

// inputChannel.transferTo(0,inputChannel.size(),outputChannel);

outputChannel.transferFrom(inputChannel,0,inputChannel.size());

}catch (Exception e){

e.printStackTrace();

}

}

java bytebuffer_聊聊JAVA的ByteBuffer相关推荐

  1. gc java root_聊聊Java的GC机制

    原标题:聊聊Java的GC机制 近日,MIUI在小米全球社区发布公告,表示MIUI将在全球市场销售的手机中预装谷歌拨号及谷歌消息应用程序(中国.印度.印度尼西亚等市场除外).小米表示,小米9T Pro ...

  2. java stw_聊聊JAVA GC系列(6) - STW

    上回介绍了"平平无奇"的标记清除算法却是JAVA GC的灵魂, 介绍的过程中留下了几个问题, 其中一个问题是: 标记清除算法正在运行时各个对象的依赖关系发生了变化怎么办? 我们先假 ...

  3. 《开源者说》08期:聊聊Java那些事儿

    <开源者说>08期:聊聊Java那些事儿 发表于2015-06-10 18:23| 4388次阅读| 来源CSDN| 28 条评论| 作者陈秋歌 Java开源者说 陈阳宫力许斌 摘要:20 ...

  4. 在Java中使用FileChannel和ByteBuffer对文件进行读写

    过去,我讨论过RandomAccessFile以及如何将其用于在Java中进行更快的IO,在本Java NIO教程中,我们将了解如何通过使用FileChannel和ByteBuffer来使用读/写数据 ...

  5. 使用Java中的FileChannel和ByteBuffer在文件中读取/写入文件

    过去,我讨论过RandomAccessFile以及如何将其用于在Java中进行更快的IO,在本Java NIO教程中,我们将了解如何通过使用FileChannel和ByteBuffer来使用读/写数据 ...

  6. java整段标记_聊聊JAVA GC系列(7) - 标记整理算法

    在介绍"平平无奇"的标记清除算法时, 还留下了另一个问题, 就是内存碎片的问题. 内存碎片的问题是指, 每次回收的内存都是比较分散的, 可以加起来是一个比较大的数值, 但是由于可用 ...

  7. java 获取泛型_聊聊Java泛型擦除那些事

    >版权申明]非商业目的注明出处可自由转载 博文地址:https://blog.csdn.net/ShuSheng0007/article/details/89789849 出自:shushen ...

  8. 敞开心扉,一起聊聊Java多线程

    目录 敞开心扉,一起聊聊Java多线程(结尾有福利~) 一.线程的实现方式 1.继承Thread类,重写run方法 2.实现Runnable接口,重写run方法 3.实现Callable接口重写run ...

  9. 6年Java老鸟聊聊新人到底要不要学Java,从事互联网《打工人的那些事》

    6年Java老鸟聊聊新人到底要不要学Java,从事互联网<打工人的那些事> 文章目录 为什么有本文 一些客观事实 优势 劣势 点题 数据来源参考地址 大家为什么选择互联网编程这条路,估摸着 ...

最新文章

  1. 实现php实现价格的排序,php 数组动态添加实现代码(最土团购系统的价格排序)_PHP教程...
  2. HDU-2044-一只小蜜蜂
  3. 春天闻香食花——品尝一顿愉悦的花餐
  4. Mac 完全卸载 Java
  5. 能够抑制网络风暴的是?
  6. pthread_join
  7. jar 命令 打包装class文件的文件夹
  8. 星尘小组第八周翻译-数据页和数据行
  9. java实现各种算法
  10. 计算机网络同步技术,计算机网络同步技术
  11. 1.2_配置Python基本环境
  12. java保留两位小数怎么_java保留两位小数4种方法
  13. Unity插件——Odin 学习笔记(二)
  14. Maix Bit K210人脸识别(内有获取机器码步骤)【保姆级教程】
  15. MySQL 升级--1
  16. 简述锂离子电池的分类及结构
  17. 点与有向线段的位置关系
  18. win10启动项在什么地方
  19. 实现简单的自定义音乐播放器
  20. 前端开发面试题整理(摘抄)

热门文章

  1. php app调试,php – 如何调试IE11 APPCACHE
  2. jquery unbind 异步_jQuery中的内置方法:unbind()
  3. python网页编辑器-史上超强 Python 编辑器,竟然是张网页?!
  4. strtol的返回值
  5. CocoaPods使用笔记
  6. JavaScript使用改变scrollLeft的值做轮播图效果
  7. 全球及中国成人奶粉行业研究及十四五规划分析报告
  8. [linux] shell 变量 字符串 数组
  9. CSS里的 no-repeat
  10. 《NFL橄榄球》:辛辛那提猛虎·橄榄1号位