标签:rtb res 支持 read gui tac pre eset 特定
同步和异步的区别最大在于异步的话调用者不需要等待处理结果,被调用者会通过回调等机制来通知调用者其返回结果。
举个生活中简单的例子,你妈妈让你烧水,小时候你比较笨啊,在那里傻等着水开(同步阻塞)。
等你稍微再长大一点,你知道每次烧水的空隙可以去干点其他事,然后只需要时不时来看看水开了没有(同步非阻塞)。
后来,你们家用上了水开了会发出声音的壶,这样你就只需要听到响声后就知道水开了,在这期间你可以随便干自己的事情,你需要去倒水了(异步非阻塞)。
在 Java NIO 中负责数据的存取。缓冲区就是数组。用于存储不同数据类型的数据。
/* * 根据数据类型不同(boolean 除外),提供了相应类型的缓冲区: * ByteBuffer * CharBuffer * ShortBuffer * IntBuffer * LongBuffer * FloatBuffer * DoubleBuffer * * 上述缓冲区的管理方式几乎一致,通过 allocate() 获取缓冲区 */
Buffer 所有子类提供了两个用于数据操作的方法:get() 与 put()
获取 Buffer 中的数据
放入数据到 Buffer 中
其它方法
// 分配缓冲区:JVM 内存中 ByteBuffer buf = ByteBuffer.allocateDirect(1024); // 分配直接缓冲区:本地内存中 ByteBuffer bufDirect = ByteBuffer.allocateDirect(1024); // 是否为直接缓冲区 System.out.println(buf.isDirect()); // 直接字节缓冲区还可以通过 FileChannel 的 map() 方法将文件区域直接映射到内存中来创建。该方法返回 MappedByteBuffer。
非直接缓冲区
直接缓冲区
import org.junit.Test; import java.nio.ByteBuffer; public class TestBuffer { @Test public void markAndReset() { String str = "abcde14693090"; // 分配直接缓冲区 ByteBuffer buf = ByteBuffer.allocateDirect(1024); // 存入数据 buf.put(str.getBytes()); // 切换到读取模式 buf.flip(); byte[] dst = new byte[buf.limit()]; buf.get(dst, 0, 2); System.out.println(new String(dst, 0, 2)); System.out.println(buf.position()); // mark() : 标记 buf.mark(); buf.get(dst, 2, 2); System.out.println(new String(dst, 2, 2)); System.out.println(buf.position()); // reset() : 恢复到 mark 的位置 buf.reset(); System.out.println(buf.position()); // 判断缓冲区中是否还有剩余数据 if (buf.hasRemaining()) { // 获取缓冲区中可以操作的数量 System.out.println(buf.remaining()); } } @Test public void getAndPut() { String str = "abcde"; //1. 分配一个指定大小的缓冲区 ByteBuffer buf = ByteBuffer.allocate(1024); System.out.println("allocate():" + buf.position() + "\t" + buf.limit() + "\t" + buf.capacity()); //2. 利用 put() 存入数据到缓冲区中 buf.put(str.getBytes()); System.out.println("put():" + buf.position() + "\t" + buf.limit() + "\t" + buf.capacity()); //3. 切换读取数据模式 buf.flip(); System.out.println("flip():" + buf.position() + "\t" + buf.limit() + "\t" + buf.capacity()); //4. 利用 get() 读取缓冲区中的数据 byte[] dst = new byte[buf.limit()]; buf.get(dst); System.out.println(new String(dst, 0, dst.length)); System.out.println("get():" + buf.position() + "\t" + buf.limit() + "\t" + buf.capacity()); //5. rewind() : 可重复读 buf.rewind(); System.out.println("rewind():" + buf.position() + "\t" + buf.limit() + "\t" + buf.capacity()); //6. clear() : 清空缓冲区. 但是缓冲区中的数据依然存在,只是处于“被遗忘”状态 buf.clear(); System.out.println("clear():" + buf.position() + "\t" + buf.limit() + "\t" + buf.capacity()); // 获取单个字符 System.out.println((char) buf.get()); } }
表示 IO 源与目标节点打开的连接,在 Java NIO 中负责缓冲区中数据的传输,类似于传统的“流”。只不过 Channel 本身不能直接访问数据,只能与 Buffer 进行交互。
/* * java.nio.channels.Channel 接口的主要实现类: * |--FileChannel:用于读取、写入、映射和操作文件的通道。 * |--SocketChannel:通过 TCP 读写网络中的数据。 * |--DatagramChannel:通过 UDP 读写网络中的数据通道。 * |--ServerSocketChannel:可以监听新进来的 TCP 连接,对每一个新进来的连接都会创建一个 SocketChannel。 */
/* * 获取通道的一种方式是对支持通道的对象调用 getChannel() 方法。 * 支持通道的类如下: * 本地 IO: * |--FileInputStream * |--FileOutputStream * |--RandomAccessFile * 网络 IO: * |--Socket * |--ServerSocket * |--DatagramSocket * * 在 JDK 1.7 中, NIO.2 针对各个通道的实现类提供了静态方法 open() 来获取通道。 * 在 JDK 1.7 中, NIO.2 的 Files 工具类的静态方法 newByteChannel() 也可以获取通道。 */
/* * 将 Buffer 中数据写入 Channel * int bytesWritten = inChannel,write(buf) * 从 Channel 读取数据到 Buffer * int bytesRead = inChannel.read(buf) * * Channel 之间的数据传输(将数据从源通道传输到其他 Channel 中) * transferFrom() * transferTo() */
复制文件的几种方式
// 通道之间的数据传输(直接缓冲区) @Test public void channelCopy() throws IOException { FileChannel inChannel = FileChannel.open(Paths.get("D:/123.txt"), StandardOpenOption.READ); FileChannel outChannel = FileChannel.open(Paths.get("D:/456.txt"), StandardOpenOption.WRITE, StandardOpenOption.READ, StandardOpenOption.CREATE); // inChannel.transferTo(0, inChannel.size(), outChannel); outChannel.transferFrom(inChannel, 0, inChannel.size()); inChannel.close(); outChannel.close(); } // 使用直接缓冲区完成文件的复制(内存映射文件) @Test public void byteBuffCopy() { long start = System.currentTimeMillis(); try (FileChannel inChannel = FileChannel.open(Paths.get("D:/123.txt"), StandardOpenOption.READ); FileChannel outChannel = FileChannel.open(Paths.get("D:/456.txt"), StandardOpenOption.WRITE, StandardOpenOption.READ, StandardOpenOption.CREATE)) { // 内存映射文件 MappedByteBuffer inMappedBuf = inChannel.map(MapMode.READ_ONLY, 0, inChannel.size()); MappedByteBuffer outMappedBuf = outChannel.map(MapMode.READ_WRITE, 0, inChannel.size()); // 直接对缓冲区进行数据的读写操作 byte[] dst = new byte[inMappedBuf.limit()]; inMappedBuf.get(dst); outMappedBuf.put(dst); } catch (IOException e) { e.printStackTrace(); } long end = System.currentTimeMillis(); System.out.println("耗费时间为:" + (end - start)); } // 利用通道完成文件的复制(非直接缓冲区) @Test public void fileCopy() { long start = System.currentTimeMillis(); try (FileInputStream fis = new FileInputStream("D:/123.txt"); FileOutputStream fos = new FileOutputStream("D:/456.txt"); // 获取通道 FileChannel inChannel = fis.getChannel(); FileChannel outChannel = fos.getChannel()) { // 分配指定大小的缓冲区 ByteBuffer buf = ByteBuffer.allocate(1024); // 将通道中的数据存入缓冲区中 while (inChannel.read(buf) != -1) { // 切换读取数据的模式 buf.flip(); // 将缓冲区中的数据写入通道中 outChannel.write(buf); // 清空缓冲区 buf.clear(); } } catch (IOException e) { e.printStackTrace(); } long end = System.currentTimeMillis(); System.out.println("Time:" + (end - start)); }
分散读取(Scattering Reads):从 Channel 中读取的数据“分散”到多个 Buffer 中。(按照缓冲区的顺序,从 Channel 中读取的数据依次将 Buffer 填满。)
聚集写入(Gathering Writes):将多个 Buffer 中的数据“聚集”到 Channel。(按照缓冲区的顺序,写入 position 和 limit 之间的数据到 Channel 。)
使用分散和聚集来复制文件部分内容
// 分散和聚集 @Test public void scatterAndGather() throws IOException { RandomAccessFile raf1 = new RandomAccessFile("D:/123.txt", "rw"); // 获取通道 FileChannel channel1 = raf1.getChannel(); // 分配指定大小的缓冲区 ByteBuffer buf1 = ByteBuffer.allocate(100); ByteBuffer buf2 = ByteBuffer.allocate(1024); // 分散读取 ByteBuffer[] bufs = {buf1, buf2}; channel1.read(bufs); // 转换模式 for (ByteBuffer byteBuffer : bufs) { byteBuffer.flip(); } System.out.println(new String(bufs[0].array(), 0, bufs[0].limit())); System.out.println("-----------------"); System.out.println(new String(bufs[1].array(), 0, bufs[1].limit())); // 聚集写入 RandomAccessFile raf2 = new RandomAccessFile("D:/456.txt", "rw"); FileChannel channel2 = raf2.getChannel(); channel2.write(bufs); }
/* * 字符集:Charset * 编码:字符串 -> 字节数组 * 解码:字节数组 -> 字符串 */ @Test public void testCharset() throws IOException { // 指定字符集 Charset cs1 = Charset.forName("GBK"); CharBuffer cBuf = CharBuffer.allocate(1024); cBuf.put("字符集"); cBuf.flip(); //获取编码器 CharsetEncoder ce = cs1.newEncoder(); //编码 ByteBuffer bBuf = ce.encode(cBuf); System.out.println(Arrays.toString(bBuf.array())); bBuf.flip(); //获取解码器 CharsetDecoder cd = cs1.newDecoder(); //解码 cBuf = cd.decode(bBuf); System.out.println(cBuf.toString()); } // Java 支持的字符集 @Test public void getCharset() { Map<String, Charset> map = Charset.availableCharsets(); for (Entry<String, Charset> entry : map.entrySet()) { System.out.println(entry.getKey() + "=" + entry.getValue()); } }
https://snailclimb.gitee.io/javaguide/#/java/BIO-NIO-AIO
https://snailclimb.gitee.io/javaguide/#/java/Java%20IO%E4%B8%8ENIO
https://cyc2018.github.io/CS-Notes/#/notes/Java%20IO?id=%e4%b8%83%e3%80%81nio
https://www.cnblogs.com/dolphin0520/p/3919162.html
https://ifeve.com/java-nio-all/
标签:rtb res 支持 read gui tac pre eset 特定
原文地址:https://www.cnblogs.com/jhxxb/p/11272727.html