您的位置:首页 > 其它

Nio简单介绍,本地操作,通道,缓冲区的简单使用,编码和解码

2017-05-27 11:11 537 查看

关于NIO

简介

javaNIO 是java1.4引入的新的IO API,可以替代java io API ,NIO和IO有同样的作用和目的,但是使用方式不同。NIO支持面向缓冲区的,基本的通道IO操作,NIO将以更加高效的方式进行文件的读写操作。

NIO和传统的IO的区别

NIOIO
面向缓冲区(Buffer)面向流(stream)
非阻塞阻塞
选择器
IO可以看作是水流,是单向的,NIO是通道连接,通道没有数据,通道负责链接,数据在缓冲区中。通过缓冲区传输数据,而且是双向的。

关于本地通信

通道和缓冲区

NIO系统的核心就是通道(channel)和缓冲区(Buffer),通道表示IO设备的连接,若使用NIO系统需要获取链接IO设备的通道和用于容纳数据的缓冲区,然后造作缓冲区,对数据进行处理。

缓冲区的数据存取

缓冲区用于数据的存取。底层是数组实现。

根据数据类型不同提供了,相应类型的缓冲区。

我们以最常见的ByteBuffer为例

/ ** capacity 缓冲区的最大存储数据容量,大小不变 limit 界限,缓冲区中可以操作数据的大小(limit后) position
* 位置,缓冲区中正在操作的位置
*
*/ mark 标记,用于记录position的位置,用reset()恢复到mark的位置
public class TestBuffer {
public static void main(String[] args) {
String string = "abcde";
// 分配指定大小的缓冲区
ByteBuffer bb = ByteBuffer.allocate(1024);
// 存取缓冲区数据
bb.put(string.getBytes());
bb.flip();// 切换成读取数据的模式
byte[] bytes = new byte[bb.limit()];
bb.get(bytes);// 读取缓冲区的数据
System.out.println(new String(bytes, 0, bytes.length));
bb.rewind();// 可以重复 读
bb.clear();// 清空缓冲区,数据没有被清空依然存在,,处于被遗忘状态,不知道数据的多少
}
}


直接缓冲区与非直接缓冲区(Buffer)

非直接缓冲区:通过allocate()方法分配的缓冲区,将缓冲区建立在JVM的内存中

直接缓冲区:通过allocateDirect()方法分配的缓冲区,将缓冲区建立在操作系统的物理内存中可以提高效率,但是不安全,消耗大,数据写到内存映射文件中后,不能控制。

通道(Channel)

一、通道(Channel):用于源节点与目标节点的连接。在 Java NIO 中负责缓冲区中数据的传输。Channel 本身不存储数据,因此需要配合缓冲区进行传输。

二、通道的主要实现类

java.nio.channels.Channel 接口:

|–FileChannel

|–SocketChannel

|–ServerSocketChannel

|–DatagramChannel

三、获取通道

Java 针对支持通道的类提供了 getChannel() 方法

本地 IO:

FileInputStream/FileOutputStream

RandomAccessFile

网络IO:

Socket

ServerSocket

DatagramSocket

在 JDK 1.7 中的 NIO.2 针对各个通道提供了静态方法 open()

在 JDK 1.7 中的 NIO.2 的 Files 工具类的 newByteChannel()

四、通道之间的数据传输

transferFrom()

transferTo()

五、分散(Scatter)与聚集(Gather)

分散读取(Scattering Reads):将通道中的数据分散到多个缓冲区中

聚集写入(Gathering Writes):将多个缓冲区中的数据聚集到通道中

六、字符集:Charset

编码:字符串 -> 字节数组

解码:字节数组 -> 字符串

package jnio;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileChannel.MapMode;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;

import org.junit.Test;

public class TestChannel {

@Test
// 使用直接缓冲区完成文件的复制(映射文件)
public void test2() throws IOException {
// 获取管道
FileChannel inChannel = FileChannel.open(Paths.get("1.jpg"),
StandardOpenOption.READ);
FileChannel outChannel = FileChannel.open(Paths.get("3.jpg"),
StandardOpenOption.WRITE, StandardOpenOption.CREATE_NEW,
StandardOpenOption.READ);

// 内存映射文件
MappedByteBuffer inMappedByteBuffer = inChannel.map(MapMode.READ_ONLY,
0, inChannel.size());
MappedByteBuffer outMappedByteBuffer = outChannel.map(
MapMode.READ_WRITE, 0, inChannel.size());

// 直接对内存映射文件进行读取
byte[] dst = new byte[inMappedByteBuffer.limit()];
inMappedByteBuffer.get(dst);
outMappedByteBuffer.put(dst);

inChannel.close();
outChannel.close();

}

@Test
// 使用通道完成文件的复制(非直接缓冲区)
public void test1() {
FileInputStream fis = null;
FileOutputStream fos = null;
// 获取通道
FileChannel inchannel = null;
FileChannel outchannel = null;
try {
fis = new FileInputStream("H:\\BaiduYunDownload\\nio.zip");
fos = new FileOutputStream("H:\\BaiduYunDownload\\nio4.zip");
// 获取通道
inchannel = fis.getChannel();
outchannel = fos.getChannel();
// 分配缓冲区
ByteBuffer buffer = ByteBuffer.allocate(1024);

// 将通道中的数据写入缓冲区
while (inchannel.read(buffer) != -1) {
buffer.flip();
outchannel.write(buffer);
buffer.clear();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (outchannel != null) {
try {
outchannel.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (inchannel != null) {
try {
inchannel.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}

}
@Test
public void test3() throws IOException{
FileChannel inChannel = FileChannel.open(Paths.get("H:\\BaiduYunDownload\\nio.zip"),
StandardOpenOption.READ);
FileChannel outChannel = FileChannel.open(Paths.get("H:\\BaiduYunDownload\\nio2.zip"),
StandardOpenOption.WRITE, StandardOpenOption.CREATE_NEW,
StandardOpenOption.READ);
inChannel.transferTo(0, inChannel.size(), outChannel);
inChannel.close();
outChannel.close();
}
}


分散读取和聚集写入

分散读取(Scattering Reads)将通道中的数据分散到多个缓冲区中,按顺序存储

聚集写入(Gathering Writes):将多个缓冲区中的数据聚集到通道中,按顺序写入

@Test
//分散读取和聚集写入
public void test4() throws Exception{
RandomAccessFile raf1 = new RandomAccessFile("1.jpg", "rw");
//获取通道
FileChannel fileChannel = raf1.getChannel();
//分配缓冲区大小
ByteBuffer buf1 = ByteBuffer.allocate(100);
ByteBuffer buf2 = ByteBuffer.allocate(1024);

ByteBuffer[] buffers = {buf1,buf2};
//读取
fileChannel.read(buffers);

System.out.println(new String(buffers[0].toString()));

//写入
for (int i = 0; i < buffers.length; i++) {
buffers[i].flip();
}

RandomAccessFile raf2 = new RandomAccessFile("5.jpg","rw");
FileChannel fileChannel2 = raf2.getChannel();

fileChannel2.write(buffers);
}


编码和解码

public void test5() throws IOException{
Charset charset = Charset.forName("GBK");
//获取编码器与解码器
CharsetEncoder encoder = charset.newEncoder();
CharsetDecoder decoder = charset.newDecoder();
CharBuffer buffer = CharBuffer.allocate(1024);
buffer.put("赵建银");
buffer.flip();
//编码
ByteBuffer buffer2 = encoder.encode(buffer);
buffer2.flip();
CharBuffer buffer3 = decoder.decode(buffer2);
System.out.println(buffer3.toString());
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  nio 编码 缓冲区 通道