NIO详解----NIO与传统IO的区别 ,NIO的原理和使用

简介: 传统IO是面向流,NIO是面向缓冲区

传统IO是面向流,NIO是面向缓冲区


面向流的传统IO建立的通道是单向的,NIO创建的通道是双向的


NIO的核心在于,通道和缓冲区。通道表示打开到IO设备的连接,若需要使用NIO,需要获取用于连接IO设备的通道以及用于容纳数据的缓冲区。然后操作缓冲区,对数据进行处理。


简而言之就是 通道负责传输,缓冲区负责存储。


1> 缓冲区

缓冲区的底层用的就是数组,根据传输数据类型的不同,java为我们提供了相应类型的缓冲区


ByteBuffer、CharBuffer、ShortBuffer、IntBuffer、LongBuffer、FloatBuffer、DoubleBuffer


很显然,ByteBuffer是最常用的,因为在磁盘或网络中传输文件都是用的字节。


这些缓冲区的管理方式基本一致,都是通过allocate()方法获取一个缓冲区。


       //分配一个指定大小的缓冲区

       ByteBuffer buf = ByteBuffer.allocate(1024);

2>缓冲区中的四个核心属性

capacity:容量,表示缓冲区中最大存储输的容量,一旦声明不能改变


limit:界限,表示缓冲区中可以操作数据的大小。即 limit后面的数据不能读写


position:位置,表示缓冲区中正在操作数据的位置


mark:标记当前position的位置,position位置改变后,可以通过reset方法来使其恢复到mark标记的位置


       System.out.println(buf.position());//输出0

       System.out.println(buf.limit());//输出1024

       System.out.println(buf.capacity());//输出1024

此时缓冲区应该是这样的,下面是一个大小是10的缓冲区



3>缓冲区存取数据

put方法,往缓冲区存数据


get方法,从缓冲区取数据


buf.put("abc".getBytes());

此时缓冲区是下面这个样子,此时的模式是写数据模式。如果此时使用get方法获取数据,是获取不到数据的,因为position之后是没有数据的。



所以我们现在再来输出一下这三个属性的值

System.out.println(buf.position());//输出3
        System.out.println(buf.limit());//输出1024
        System.out.println(buf.capacity());//输出1024

flip方法,切换到读数据模式,position会回到起点


buf.flip();

此时的缓冲区是这样的,limit界限变成了刚才存入数据的长度



这时候我们再来输出一下三个属性的值


       System.out.println(buf.position());//输出0

       System.out.println(buf.limit());//输出3

       System.out.println(buf.capacity());//输出1024

使用get方法读取内容


       byte[] b = new byte[buf.limit()];//创建一个字节数组,长度为缓冲区limit界限的值

       buf.get(b);//读出内容到指定的字节数组

       System.out.println(new String(b,0,b.length));//输出abc

此时的缓冲区是这样的



输出一下三个属性的值


       System.out.println(buf.position());//输出3

       System.out.println(buf.limit());//输出3

       System.out.println(buf.capacity());//输出1024

rewind方法,重新读数据,三个属性回到执行flip方法后的值


clear方法,清空缓冲区,但是这个方法只会把单个属性的值回到初始状态,而缓冲区中的数据不会删除,只是数据会处于一个被遗忘状态。


hasRemaining方法,判断缓冲区中是否有可操作的数据,


remaining方法,获取可操作数据的数量


       if(buf.hasRemaining()){

           //如果有可操作的数据,输出可操作数据的数量

           System.out.println(buf.remaining());

       }

4>直接缓冲区和非直接缓冲区

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


直接缓冲区:通过allocateDirect方法分配的缓冲区,将缓冲区建立在物理内存中。可以提高效率,但是消耗的资源变大。


isDirect方法用来判断是不是直接缓冲区。


5>通道(Channel)

用于源节点与目标节点的连接,在Java NIO 中负责缓冲区中数据的传输。Channel本身不能存储数据,因此需要配合缓冲区进行传输。就好比铁路需要火车配合一样。

6>通道的主要实现类

java.nio.channels.Chennel接口


   |--FileChannel       本地


   |--SocketChannel      TCP


   |--ServerSocketChannel        TCP


   |--DatagramChannel       UDP


7>获取通道

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


本地IO:


FileInputStream、FileOutputStream、RandomAccessFile


网络IO:


Socket、ServerSocket、DatagramSocket


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


3.在JDK 1.7之后的Files工具类的newByteChannel()方法


利用通道完成文件的复制(非直接缓冲区)

FileInputStream fis = null;
        FileOutputStream fos = null;
        FileChannel inChannel = null;
        FileChannel outChannel = null;
        try {
            fis = new FileInputStream("D:\\SVN_WORK\\untitled\\src\\test\\1.png");
            fos = new FileOutputStream("D:\\SVN_WORK\\untitled\\src\\test\\2.png");
            //获取通道
            inChannel = fis.getChannel();
            outChannel = fos.getChannel();
            //分配一个指定大小的缓冲区
            ByteBuffer buf = ByteBuffer.allocate(1024);
            //将通道中的数据放入缓冲区
            while (inChannel.read(buf) != -1){
                //切换到读取数据模式
                buf.flip();
                //将缓冲区的数据写入通道
                outChannel.write(buf);
                buf.clear();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            if(inChannel != null){
                try {
                    inChannel.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(outChannel != null){
                try {
                    outChannel.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(fis != null){
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(fos != null){
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }


使用直接缓冲区完成文件的复制(内存映射文件),只支持ByteBuffer


FileChannel inChannel = null;
        FileChannel outChannel = null;
        MappedByteBuffer inMappedBuf = null;
        MappedByteBuffer outMappedBuf = null;
        try{
            inChannel = FileChannel.open(Paths.get("D:\\SVN_WORK\\untitled\\src\\test\\1.png"), StandardOpenOption.READ);
            outChannel = FileChannel.open(Paths.get("D:\\SVN_WORK\\untitled\\src\\test\\3.png"),StandardOpenOption.WRITE,StandardOpenOption.READ,StandardOpenOption.CREATE);
            //内存映射文件
            inMappedBuf = inChannel.map(FileChannel.MapMode.READ_ONLY,0,inChannel.size());
            outMappedBuf = outChannel.map(FileChannel.MapMode.READ_WRITE,0,inChannel.size());
            //直接对缓冲区进行数据的读写操作
            byte[] b = new byte[inMappedBuf.limit()];
            inMappedBuf.get(b);
            outMappedBuf.put(b);
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            if(inChannel != null){
                try {
                    inChannel.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(outChannel != null){
                try {
                    outChannel.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }


通道之间的数据传输(直接缓冲区)


FileChannel inChannel = null;
        FileChannel outChannel = null;
        MappedByteBuffer inMappedBuf = null;
        MappedByteBuffer outMappedBuf = null;
        try {
            inChannel = FileChannel.open(Paths.get("D:\\SVN_WORK\\untitled\\src\\test\\1.png"), StandardOpenOption.READ);
            outChannel = FileChannel.open(Paths.get("D:\\SVN_WORK\\untitled\\src\\test\\3.png"), StandardOpenOption.WRITE, StandardOpenOption.READ, StandardOpenOption.CREATE);
            //方法1
            inChannel.transferTo(0, inChannel.size(), outChannel);
            //方法2
//            outChannel.transferFrom(inChannel,0,inChannel.size());
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (inChannel != null) {
                try {
                    inChannel.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (outChannel != null) {
                try {
                    outChannel.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }


8>分散于聚集

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


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

RandomAccessFile raf1 = null;
        RandomAccessFile raf2 = null;
        try {
            raf1 = new RandomAccessFile("1.txt", "rw");
            //1 获取通道
            FileChannel channel1 = raf1.getChannel();
            //2 分配指定大小的缓冲区
            ByteBuffer buf1 = ByteBuffer.allocate(100);
            ByteBuffer buf2 = ByteBuffer.allocate(1024);
            //3 分散读取
            ByteBuffer[] bus = {buf1,buf2};
            channel1.read(bus);
            //切换到读数据模式
            for (ByteBuffer b : bus) {
                b.flip();
            }
            //4 聚集写入
            raf2 = new RandomAccessFile("2.txt", "rw");
            FileChannel channel2 = raf2.getChannel();
            channel2.write(bus);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }


9>字符集

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


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


查看所支持的所有编码

Map<String, Charset> map = Charset.availableCharsets();
        Set<Entry<String, Charset>> set = map.entrySet();
        for (Entry<String, Charset> entry : set) {
            System.out.println(entry.getKey()+"---"+entry.getValue());
        }

输出结果:


Big5---Big5

Big5-HKSCS---Big5-HKSCS

CESU-8---CESU-8

EUC-JP---EUC-JP

EUC-KR---EUC-KR

GB18030---GB18030

GB2312---GB2312

GBK---GBK

IBM-Thai---IBM-Thai

IBM00858---IBM00858

IBM01140---IBM01140

IBM01141---IBM01141

IBM01142---IBM01142

IBM01143---IBM01143

IBM01144---IBM01144

IBM01145---IBM01145

IBM01146---IBM01146

IBM01147---IBM01147

IBM01148---IBM01148

IBM01149---IBM01149

IBM037---IBM037

IBM1026---IBM1026

IBM1047---IBM1047

IBM273---IBM273

IBM277---IBM277

IBM278---IBM278

IBM280---IBM280

IBM284---IBM284

IBM285---IBM285

IBM290---IBM290

IBM297---IBM297

IBM420---IBM420

IBM424---IBM424

IBM437---IBM437

IBM500---IBM500

IBM775---IBM775

IBM850---IBM850

IBM852---IBM852

IBM855---IBM855

IBM857---IBM857

IBM860---IBM860

IBM861---IBM861

IBM862---IBM862

IBM863---IBM863

IBM864---IBM864

IBM865---IBM865

IBM866---IBM866

IBM868---IBM868

IBM869---IBM869

IBM870---IBM870

IBM871---IBM871

IBM918---IBM918

ISO-2022-CN---ISO-2022-CN

ISO-2022-JP---ISO-2022-JP

ISO-2022-JP-2---ISO-2022-JP-2

ISO-2022-KR---ISO-2022-KR

ISO-8859-1---ISO-8859-1

ISO-8859-13---ISO-8859-13

ISO-8859-15---ISO-8859-15

ISO-8859-2---ISO-8859-2

ISO-8859-3---ISO-8859-3

ISO-8859-4---ISO-8859-4

ISO-8859-5---ISO-8859-5

ISO-8859-6---ISO-8859-6

ISO-8859-7---ISO-8859-7

ISO-8859-8---ISO-8859-8

ISO-8859-9---ISO-8859-9

JIS_X0201---JIS_X0201

JIS_X0212-1990---JIS_X0212-1990

KOI8-R---KOI8-R

KOI8-U---KOI8-U

Shift_JIS---Shift_JIS

TIS-620---TIS-620

US-ASCII---US-ASCII

UTF-16---UTF-16

UTF-16BE---UTF-16BE

UTF-16LE---UTF-16LE

UTF-32---UTF-32

UTF-32BE---UTF-32BE

UTF-32LE---UTF-32LE

UTF-8---UTF-8

windows-1250---windows-1250

windows-1251---windows-1251

windows-1252---windows-1252

windows-1253---windows-1253

windows-1254---windows-1254

windows-1255---windows-1255

windows-1256---windows-1256

windows-1257---windows-1257

windows-1258---windows-1258

windows-31j---windows-31j

x-Big5-HKSCS-2001---x-Big5-HKSCS-2001

x-Big5-Solaris---x-Big5-Solaris

x-euc-jp-linux---x-euc-jp-linux

x-EUC-TW---x-EUC-TW

x-eucJP-Open---x-eucJP-Open

x-IBM1006---x-IBM1006

x-IBM1025---x-IBM1025

x-IBM1046---x-IBM1046

x-IBM1097---x-IBM1097

x-IBM1098---x-IBM1098

x-IBM1112---x-IBM1112

x-IBM1122---x-IBM1122

x-IBM1123---x-IBM1123

x-IBM1124---x-IBM1124

x-IBM1166---x-IBM1166

x-IBM1364---x-IBM1364

x-IBM1381---x-IBM1381

x-IBM1383---x-IBM1383

x-IBM300---x-IBM300

x-IBM33722---x-IBM33722

x-IBM737---x-IBM737

x-IBM833---x-IBM833

x-IBM834---x-IBM834

x-IBM856---x-IBM856

x-IBM874---x-IBM874

x-IBM875---x-IBM875

x-IBM921---x-IBM921

x-IBM922---x-IBM922

x-IBM930---x-IBM930

x-IBM933---x-IBM933

x-IBM935---x-IBM935

x-IBM937---x-IBM937

x-IBM939---x-IBM939

x-IBM942---x-IBM942

x-IBM942C---x-IBM942C

x-IBM943---x-IBM943

x-IBM943C---x-IBM943C

x-IBM948---x-IBM948

x-IBM949---x-IBM949

x-IBM949C---x-IBM949C

x-IBM950---x-IBM950

x-IBM964---x-IBM964

x-IBM970---x-IBM970

x-ISCII91---x-ISCII91

x-ISO-2022-CN-CNS---x-ISO-2022-CN-CNS

x-ISO-2022-CN-GB---x-ISO-2022-CN-GB

x-iso-8859-11---x-iso-8859-11

x-JIS0208---x-JIS0208

x-JISAutoDetect---x-JISAutoDetect

x-Johab---x-Johab

x-MacArabic---x-MacArabic

x-MacCentralEurope---x-MacCentralEurope

x-MacCroatian---x-MacCroatian

x-MacCyrillic---x-MacCyrillic

x-MacDingbat---x-MacDingbat

x-MacGreek---x-MacGreek

x-MacHebrew---x-MacHebrew

x-MacIceland---x-MacIceland

x-MacRoman---x-MacRoman

x-MacRomania---x-MacRomania

x-MacSymbol---x-MacSymbol

x-MacThai---x-MacThai

x-MacTurkish---x-MacTurkish

x-MacUkraine---x-MacUkraine

x-MS932_0213---x-MS932_0213

x-MS950-HKSCS---x-MS950-HKSCS

x-MS950-HKSCS-XP---x-MS950-HKSCS-XP

x-mswin-936---x-mswin-936

x-PCK---x-PCK

x-SJIS_0213---x-SJIS_0213

x-UTF-16LE-BOM---x-UTF-16LE-BOM

X-UTF-32BE-BOM---X-UTF-32BE-BOM

X-UTF-32LE-BOM---X-UTF-32LE-BOM

x-windows-50220---x-windows-50220

x-windows-50221---x-windows-50221

x-windows-874---x-windows-874

x-windows-949---x-windows-949

x-windows-950---x-windows-950

x-windows-iso2022jp---x-windows-iso2022jp



编码解码


Charset cs1 = Charset.forName("GBK");
        //获取编码器
        CharsetEncoder ce = cs1.newEncoder();
        //获取解码器
        CharsetDecoder cd = cs1.newDecoder();
        CharBuffer cBuf = CharBuffer.allocate(1024);
        cBuf.put("刘海柱");
        cBuf.flip();
        try {
            //编码
            ByteBuffer bBuf = ce.encode(cBuf);
            //解码
            bBuf.flip();
            CharBuffer cBuf2 = cd.decode(bBuf);
            System.out.println(cBuf2.toString());//输出刘海柱
            //用utf-8解码
            Charset.forName("utf-8").newDecoder().decode(bBuf);//输出乱码
        } catch (CharacterCodingException e) {
            e.printStackTrace();
        }


10>NIO阻塞式与非阻塞式

这个阻塞式与非阻塞式主要是针对的网络IO,非阻塞式可以让服务端减少不必要的等待


先来看一下使用阻塞式的方式


//客户端
    @Test
    public void client(){
        SocketChannel sChannel = null;
        FileChannel inChannel = null;
        try {
            //1,获取通道
            sChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1", 8998));
           inChannel = FileChannel.open(Paths.get("1.png"), StandardOpenOption.READ);
           //2,分配指定大小的缓冲区
            ByteBuffer buf = ByteBuffer.allocate(1024);
            //3,读取本地文件,并发送到服务器
            while(inChannel.read(buf) != -1){
                buf.flip();
                sChannel.write(buf);
                buf.clear();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            //关闭通道
            if(sChannel != null){
                try {
                    sChannel.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(inChannel != null){
                try {
                    inChannel.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    //服务端
    @Test
    public void server(){
        ServerSocketChannel ssChannel = null;
        FileChannel outChannel = null;
        SocketChannel sChannel = null;
        try {
            //1,获取通道
            ssChannel = ServerSocketChannel.open();
            outChannel = FileChannel.open(Paths.get("2.png"),StandardOpenOption.WRITE,StandardOpenOption.CREATE);
            //2,绑定连接
            ssChannel.bind(new InetSocketAddress(8998));
            //3,获取客户端连接的通道
            sChannel = ssChannel.accept();
            //4,分配指定大小的缓冲区
            ByteBuffer buf = ByteBuffer.allocate(1024);
            //5,接收客户端的数据,并保存到本地
            while (sChannel.read(buf) != -1){
                buf.flip();
                outChannel.write(buf);
                buf.clear();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            //6,关闭通道
            if(ssChannel != null){
                try {
                    ssChannel.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(outChannel != null){
                try {
                    outChannel.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(sChannel != null){
                try {
                    sChannel.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }


非阻塞式


//非阻塞式客户端
    @Test
    public void client1() {
        SocketChannel sChannel = null;
        try {
            //1,获取通道
            sChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1", 8998));
            //2,切换到非阻塞式
            sChannel.configureBlocking(false);
            //3,分配指定大小的缓冲区
            ByteBuffer buf = ByteBuffer.allocate(1024);
            //4,发送数据到服务端
            buf.put("刘海柱".getBytes());
            buf.flip();
            sChannel.write(buf);
            buf.clear();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //5,关闭通道
            if (sChannel != null) {
                try {
                    sChannel.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    //非阻塞式服务端
    @Test
    public void server1() {
        ServerSocketChannel ssChannel = null;
        SocketChannel sChannel = null;
        try {
            //1,获取通道
            ssChannel = ServerSocketChannel.open();
            //2,切换非阻塞模式
            ssChannel.configureBlocking(false);
            //3,绑定连接
            ssChannel.bind(new InetSocketAddress(8998));
            //4,获取选择器
            Selector selector = Selector.open();
            //5,将通道注册到选择器上,并指定“监听接收事件”,监听连接事件
            ssChannel.register(selector, SelectionKey.OP_ACCEPT);
            //6,轮询式的获取选择器上已经准备就绪的事件
            while(selector.select() > 0){
                //7,获取当前选择器中所有注册的“选择键(已就绪的监听事件)”
                Iterator<SelectionKey> it = selector.selectedKeys().iterator();
                while(it.hasNext()){
                    //8,获取准备就绪的事件
                    SelectionKey sk = it.next();
                    //9,具体判断是什么事件准备就绪
                    if(sk.isAcceptable()){
                        //10,如果接收就绪,获取客户端连接的通道
                        sChannel = ssChannel.accept();
                        //11,切换到非阻塞模式
                        sChannel.configureBlocking(false);
                        //12,将该通道注册到选择器,监听读就绪状态
                        sChannel.register(selector,SelectionKey.OP_READ);
                    }else if(sk.isReadable()){
                        //13,获取当前选择器上读就绪状态的通道
                        sChannel = (SocketChannel) sk.channel();
                        //14,读取数据
                        ByteBuffer buf = ByteBuffer.allocate(1024);
                        int len = 0;
                        while ((len = sChannel.read(buf)) > 0) {
                            buf.flip();
                            System.out.println(new String(buf.array(),0,len));
                        }
                    }
                    //15,取消选择键(SelectionKey)
                    it.remove();
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //6,关闭通道
            if (ssChannel != null) {
                try {
                    ssChannel.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (sChannel != null) {
                try {
                    sChannel.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

上面使用的是TCP方式,下面使用UDP方式传输数据


//发送端
    @Test
    public void send() {
        DatagramChannel dc = null;
        try {
            //获取通道
            dc = DatagramChannel.open();
            //切换到非阻塞模式
            dc.configureBlocking(false);
            //缓冲区
            ByteBuffer buf = ByteBuffer.allocate(1024);
            //缓冲区中添加数据
            buf.put(new Date().toString().getBytes());
            //切换到读取模式
            buf.flip();
            //发送
            dc.send(buf, new InetSocketAddress("127.0.0.1", 8999));
            //清空缓冲区
            buf.clear();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (dc != null) {
                try {
                    //关闭通道
                    dc.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    //接收端
    @Test
    public void receive() {
        DatagramChannel dc = null;
        try {
            //获取通道
            dc = DatagramChannel.open();
            //切换到非阻塞模式
            dc.configureBlocking(false);
            //绑定连接
            dc.bind(new InetSocketAddress(8999));
            //打开选择器
            Selector selector = Selector.open();
            //把通道注册到选择器,监听读
            dc.register(selector, SelectionKey.OP_READ);
            //轮询获取数据
            while(selector.select() > 0){
                Iterator<SelectionKey> it = selector.selectedKeys().iterator();
                while(it.hasNext()){
                    SelectionKey sk = it.next();
                    //如果读就绪
                    if(sk.isReadable()){
                        ByteBuffer buf = ByteBuffer.allocate(1024);
                        //接收数据
                        dc.receive(buf);
                        buf.flip();
                        System.out.println(new String(buf.array(),0,buf.limit()));
                        buf.clear();
                    }
                }
                it.remove();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if(dc != null){
                try {
                    //关闭通道
                    dc.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

11>管道(Pipe)

Java NIO 管道是两个线程之间的单向数据连接。Pipe有一个source通道和一个sink通道。数据会被写到sink通道,从source通道读取。

Pipe pipe = null;
        SinkChannel sinkChannel = null;
        SourceChannel sourceChannel = null;
        try {
            //1,获取管道
            pipe = Pipe.open();
            //2,缓冲区
            ByteBuffer buf = ByteBuffer.allocate(1024);
            buf.put("单向管道发送数据".getBytes());
            buf.flip();
            //3,获取通道
            sinkChannel = pipe.sink();
            //4,发送数据
            sinkChannel.write(buf);
            //5,读取数据
            sourceChannel = pipe.source();
            buf.flip();
            int len = sourceChannel.read(buf);
            System.out.println(new String(buf.array(),0,len));
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if(sinkChannel != null){
                try {
                    sinkChannel.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(sourceChannel != null){
                try {
                    sourceChannel.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }


相关文章
|
7天前
|
网络协议 Dubbo Java
一文搞懂NIO、AIO、BIO的核心区别(建议收藏)
本文详细解析了NIO、AIO、BIO的核心区别,NIO的三个核心概念,以及NIO在Java框架中的应用等。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
一文搞懂NIO、AIO、BIO的核心区别(建议收藏)
|
4月前
|
Java 大数据
解析Java中的NIO与传统IO的区别与应用
解析Java中的NIO与传统IO的区别与应用
|
1月前
|
自然语言处理 Java 数据处理
Java IO流全解析:字节流和字符流的区别与联系!
Java IO流全解析:字节流和字符流的区别与联系!
74 1
|
2月前
|
Java 大数据 API
Java 流(Stream)、文件(File)和IO的区别
Java中的流(Stream)、文件(File)和输入/输出(I/O)是处理数据的关键概念。`File`类用于基本文件操作,如创建、删除和检查文件;流则提供了数据读写的抽象机制,适用于文件、内存和网络等多种数据源;I/O涵盖更广泛的输入输出操作,包括文件I/O、网络通信等,并支持异常处理和缓冲等功能。实际开发中,这三者常结合使用,以实现高效的数据处理。例如,`File`用于管理文件路径,`Stream`用于读写数据,I/O则处理复杂的输入输出需求。
|
1月前
|
Java Linux 应用服务中间件
【编程进阶知识】高并发场景下Bio与Nio的比较及原理示意图
本文介绍了在Linux系统上使用Tomcat部署Java应用程序时,BIO(阻塞I/O)和NIO(非阻塞I/O)在网络编程中的实现和性能差异。BIO采用传统的线程模型,每个连接请求都会创建一个新线程进行处理,导致在高并发场景下存在严重的性能瓶颈,如阻塞等待和线程创建开销大等问题。而NIO则通过事件驱动机制,利用事件注册、事件轮询器和事件通知,实现了更高效的连接管理和数据传输,避免了阻塞和多级数据复制,显著提升了系统的并发处理能力。
57 0
|
3月前
|
网络协议 Oracle Java
【IO面试题 三】、说说NIO的实现原理
Java NIO的实现原理基于Channel、Buffer和Selector,支持从Channel读取数据到Buffer以及从Buffer写入数据到Channel,并通过Selector实现单线程多Channel的事件驱动IO操作。
【IO面试题 三】、说说NIO的实现原理
|
3月前
|
缓存 Java UED
BIO、NIO、AIO有什么区别
【8月更文挑战第16天】BIO、NIO、AIO有什么区别
77 4
|
3月前
|
Java
"揭秘Java IO三大模式:BIO、NIO、AIO背后的秘密!为何AIO成为高并发时代的宠儿,你的选择对了吗?"
【8月更文挑战第19天】在Java的IO编程中,BIO、NIO与AIO代表了三种不同的IO处理机制。BIO采用同步阻塞模型,每个连接需单独线程处理,适用于连接少且稳定的场景。NIO引入了非阻塞性质,利用Channel、Buffer与Selector实现多路复用,提升了效率与吞吐量。AIO则是真正的异步IO,在JDK 7中引入,通过回调或Future机制在IO操作完成后通知应用,适合高并发场景。选择合适的模型对构建高效网络应用至关重要。
81 2
|
4月前
|
安全 Java Linux
(七)Java网络编程-IO模型篇之从BIO、NIO、AIO到内核select、epoll剖析!
IO(Input/Output)方面的基本知识,相信大家都不陌生,毕竟这也是在学习编程基础时就已经接触过的内容,但最初的IO教学大多数是停留在最基本的BIO,而并未对于NIO、AIO、多路复用等的高级内容进行详细讲述,但这些却是大部分高性能技术的底层核心,因此本文则准备围绕着IO知识进行展开。
165 1
|
4月前
|
存储 Linux 网络安全
Centos安装Docker的详细安装步骤,Docker相关组件:docker-ce-cli、docker-ce和containerd.io的区别
Centos安装Docker的详细安装步骤,Docker相关组件:docker-ce-cli、docker-ce和containerd.io的区别;CentOS7安装DockerCompose;Docker镜像仓库
699 11