Nio简单介绍,本地操作,通道,缓冲区的简单使用,编码和解码
2017-05-27 11:11
537 查看
关于NIO
简介
javaNIO 是java1.4引入的新的IO API,可以替代java io API ,NIO和IO有同样的作用和目的,但是使用方式不同。NIO支持面向缓冲区的,基本的通道IO操作,NIO将以更加高效的方式进行文件的读写操作。NIO和传统的IO的区别
NIO | IO |
---|---|
面向缓冲区(Buffer) | 面向流(stream) |
非阻塞 | 阻塞 |
选择器 | 无 |
关于本地通信
通道和缓冲区
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()); }
相关文章推荐
- Java入门系列-23-NIO(使用缓冲区和通道对文件操作)
- js编码、解码函数介绍及其使用示例
- TortoiseSVN搭建本地版本库及简单操作使用
- js编码、解码函数介绍及其使用示例
- Node.js, 使用 Buffers 操作,编码、解码,二进制数据。
- IOS使用项目中的本地数据库简单操作
- 使用技巧:简单介绍JSP数据库高级操作
- 【Git】使用Git Bash将代码托管到Git@OSC的简单操作介绍
- nio 本地文件操作之通道之间的数据传输
- js编码、解码函数介绍及其使用示例
- TortoiseSVN搭建本地版本库及简单操作使用
- 简单介绍vss工具command操作使用
- TortoiseSVN搭建本地版本库及简单操作使用
- 简单 utf8 编码、解码,可用来对数据进行加密
- 使用jxl读写excel(jxl操作excel)的简单例子
- Oracle游标使用的简单介绍
- 用vc6操作xml以及xmldom的简单介绍
- 使用System.DirectoryServices.Protocols实现对AD的简单操作
- Atlas学习手记(8):调用本地Web Service简单介绍
- 使用System.DirectoryServices.Protocols实现对AD的简单操作[转载]