java bytebuffer_聊聊JAVA的ByteBuffer
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相关推荐
- gc java root_聊聊Java的GC机制
原标题:聊聊Java的GC机制 近日,MIUI在小米全球社区发布公告,表示MIUI将在全球市场销售的手机中预装谷歌拨号及谷歌消息应用程序(中国.印度.印度尼西亚等市场除外).小米表示,小米9T Pro ...
- java stw_聊聊JAVA GC系列(6) - STW
上回介绍了"平平无奇"的标记清除算法却是JAVA GC的灵魂, 介绍的过程中留下了几个问题, 其中一个问题是: 标记清除算法正在运行时各个对象的依赖关系发生了变化怎么办? 我们先假 ...
- 《开源者说》08期:聊聊Java那些事儿
<开源者说>08期:聊聊Java那些事儿 发表于2015-06-10 18:23| 4388次阅读| 来源CSDN| 28 条评论| 作者陈秋歌 Java开源者说 陈阳宫力许斌 摘要:20 ...
- 在Java中使用FileChannel和ByteBuffer对文件进行读写
过去,我讨论过RandomAccessFile以及如何将其用于在Java中进行更快的IO,在本Java NIO教程中,我们将了解如何通过使用FileChannel和ByteBuffer来使用读/写数据 ...
- 使用Java中的FileChannel和ByteBuffer在文件中读取/写入文件
过去,我讨论过RandomAccessFile以及如何将其用于在Java中进行更快的IO,在本Java NIO教程中,我们将了解如何通过使用FileChannel和ByteBuffer来使用读/写数据 ...
- java整段标记_聊聊JAVA GC系列(7) - 标记整理算法
在介绍"平平无奇"的标记清除算法时, 还留下了另一个问题, 就是内存碎片的问题. 内存碎片的问题是指, 每次回收的内存都是比较分散的, 可以加起来是一个比较大的数值, 但是由于可用 ...
- java 获取泛型_聊聊Java泛型擦除那些事
>版权申明]非商业目的注明出处可自由转载 博文地址:https://blog.csdn.net/ShuSheng0007/article/details/89789849 出自:shushen ...
- 敞开心扉,一起聊聊Java多线程
目录 敞开心扉,一起聊聊Java多线程(结尾有福利~) 一.线程的实现方式 1.继承Thread类,重写run方法 2.实现Runnable接口,重写run方法 3.实现Callable接口重写run ...
- 6年Java老鸟聊聊新人到底要不要学Java,从事互联网《打工人的那些事》
6年Java老鸟聊聊新人到底要不要学Java,从事互联网<打工人的那些事> 文章目录 为什么有本文 一些客观事实 优势 劣势 点题 数据来源参考地址 大家为什么选择互联网编程这条路,估摸着 ...
最新文章
- 实现php实现价格的排序,php 数组动态添加实现代码(最土团购系统的价格排序)_PHP教程...
- HDU-2044-一只小蜜蜂
- 春天闻香食花——品尝一顿愉悦的花餐
- Mac 完全卸载 Java
- 能够抑制网络风暴的是?
- pthread_join
- jar 命令 打包装class文件的文件夹
- 星尘小组第八周翻译-数据页和数据行
- java实现各种算法
- 计算机网络同步技术,计算机网络同步技术
- 1.2_配置Python基本环境
- java保留两位小数怎么_java保留两位小数4种方法
- Unity插件——Odin 学习笔记(二)
- Maix Bit K210人脸识别(内有获取机器码步骤)【保姆级教程】
- MySQL 升级--1
- 简述锂离子电池的分类及结构
- 点与有向线段的位置关系
- win10启动项在什么地方
- 实现简单的自定义音乐播放器
- 前端开发面试题整理(摘抄)