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

关于NIO

简介

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


NIO和传统的IO的区别

NIOIO
面向缓冲区(Buffer)面向流(stream)
非阻塞阻塞
选择器

  1. 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

三、获取通道

  1. Java 针对支持通道的类提供了 getChannel() 方法
    本地 IO:
    FileInputStream/FileOutputStream
    RandomAccessFile
    网络IO:
    Socket
    ServerSocket
    DatagramSocket

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

  3. 在 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());
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值