一.bio与nio区别
IO | NIO |
---|---|
面向流(Stream Orientend) | 面向缓冲区(Buffer Orientend) |
阻塞IO(Blocking IO ) | 非阻塞IO(Non Blocking IO) |
选择器(Selector) |
二.通道(Channel )
通道表示打开到 IO 设备(例如:文件、套接字)的连接。若需要使用 NIO 系统,需要获取用于连接 IO 设备的通道以及用于容纳数据的缓冲区。然后操作缓冲区,对数据进行处理。
Channel相比IO中的Stream更加高效,可以异步双向传输,但是必须和buffer一起使用。
三.Channel主要实现类
FileChannel,读写文件中的数据。
SocketChannel,通过TCP读写网络中的数据。
ServerSockectChannel,监听新进来的TCP连接,像Web服务器那样。对每一个新进来的连接都会创建一个SocketChannel。
DatagramChannel,通过UDP读写网络中的数据。
四.Channel主要获取方式
1、java针对支持通道的类提供了getChannel()方法
本地io:
FileInputStreanm/FileOutputStream
RandomAccessFile
网络io:
Socket
ServerSocket
DatagramSocket
五.代码实例
package com.tcc.test.nio.channel; import org.junit.Test; import java.io.*; import java.nio.ByteBuffer; import java.nio.MappedByteBuffer; import java.nio.channels.FileChannel; /** * Copyright (C) @2021 * * @author: tcc * @version: 1.0 * @date: 2021/11/28 * @time: 17:37 * @description: */ public class channeltest { //文件复制 @Test public void test() throws Exception { FileInputStream fis = new FileInputStream("D:\\1.jpg"); FileOutputStream fos = new FileOutputStream("D:\\2.jpg"); //获取通道 FileChannel inChannel = fis.getChannel(); FileChannel outChannel = fos.getChannel(); //分配指定大小缓存区 ByteBuffer buff = ByteBuffer.allocate(1024);// position 0 ,limit 1024 //将通道的数据存入缓存区 while (inChannel.read(buff) != -1) {// position 1024 ,limit 1024 ,相当于put //切换读模式 buff.flip();//position 0 ,limit 1024 //将缓存去的数据写入通道 outChannel.write(buff);//position 1024 ,limit 1024,相当于get //清空缓冲区 buff.clear();//position 0 ,limit 1024 } outChannel.close(); inChannel.close(); fis.close(); fos.close(); } //一个文件读其中一部分 @Test public void test2() throws IOException { String fff = "D:\\test.txt"; final int BUFFER_SIZE = 0x300000;// 缓冲区大小为3M File f = new File(fff); /** * * map(FileChannel.MapMode mode,long position, long size) * * mode - 根据是按只读、读取/写入或专用(写入时拷贝)来映射文件,分别为 FileChannel.MapMode 类中所定义的 * READ_ONLY、READ_WRITE 或 PRIVATE 之一 * * position - 文件中的位置,映射区域从此位置开始;必须为非负数 * * size - 要映射的区域大小;必须为非负数且不大于 Integer.MAX_VALUE * * 所以若想读取文件后半部分内容,如例子所写;若想读取文本后1/8内容,需要这样写map(FileChannel.MapMode.READ_ONLY, * f.length()*7/8,f.length()/8) * * 想读取文件所有内容,需要这样写map(FileChannel.MapMode.READ_ONLY, 0,f.length()) * */ MappedByteBuffer inputBuffer = new RandomAccessFile(f, "r") .getChannel().map(FileChannel.MapMode.READ_ONLY, f.length() / 2, f.length() / 2); byte[] dst = new byte[BUFFER_SIZE];// 每次读出3M的内容 long start = System.currentTimeMillis(); for (int offset = 0; offset < inputBuffer.capacity(); offset += BUFFER_SIZE) { if (inputBuffer.capacity() - offset >= BUFFER_SIZE) { for (int i = 0; i < BUFFER_SIZE; i++) dst[i] = inputBuffer.get(offset + i); } else { for (int i = 0; i < inputBuffer.capacity() - offset; i++) dst[i] = inputBuffer.get(offset + i); } int length = (inputBuffer.capacity() % BUFFER_SIZE == 0) ? BUFFER_SIZE : inputBuffer.capacity() % BUFFER_SIZE; System.out.println(new String(dst, 0, length));// new // String(dst,0,length)这样可以取出缓存保存的字符串,可以对其进行操作 } long end = System.currentTimeMillis(); System.out.println("读取文件文件一半内容花费:" + (end - start) + "毫秒"); } //全部一次性读 @Test public void test3() throws IOException { String fff = "D:\\test.txt"; int bufSize = 1024; byte[] bs = new byte[bufSize]; ByteBuffer byteBuf = ByteBuffer.allocate(1024); FileChannel channel = new RandomAccessFile(fff, "r").getChannel(); while (channel.read(byteBuf) != -1) { int size = byteBuf.position(); byteBuf.rewind(); byteBuf.get(bs); // 把文件当字符串处理,直接打印做为一个例子。 System.out.print(new String(bs, 0, size)); byteBuf.clear(); } } //一行行读 @Test public void test4() throws IOException { String fff = "D:\\test.txt"; BufferedReader br = new BufferedReader(new FileReader(fff)); String line = null; while ((line = br.readLine()) != null) { System.out.println(line); } } //每次读取几行 @Test public void test5() throws IOException { String path = "D:\\test.txt"; RandomAccessFile br = new RandomAccessFile(path, "rw");//这里rw看你了。要是之都就只写r String str = null, app = null; int i = 0; while ((str = br.readLine()) != null) { i++; app = app + str; System.out.println("app=="+app); if (i >= 2) {//假设读取100行 i = 0; // 这里你先对这100行操作,然后继续读 System.out.println("app22"+app); app = null; } } br.close(); } //BufferedReader类读写超大文件,一行行读 @Test public void test6() throws IOException { String filepath = "D:\\test.txt"; File file = new File(filepath); BufferedInputStream fis = new BufferedInputStream(new FileInputStream(file)); BufferedReader reader = new BufferedReader(new InputStreamReader(fis,"utf-8"),5*1024*1024);// 用5M的缓冲读取文本文件 String line = ""; while((line = reader.readLine()) != null){ System.out.println("line==="+line); //TODO: write your business } } }