day24【模拟服务器、软件架构、Junit、NIO】课上

    技术2022-07-11  86

    1.模拟服务器(扩展)

    需求:在浏览器中访问当前项目下的资源 : web/index.html ,我们自己书写服务器,将当前项目下的index.html页面中的所有内容响应

    代码演示:

    package com.itheima.sh.server_01; import java.io.*; import java.net.ServerSocket; import java.net.Socket; /* 模拟服务器 */ public class ServerDemo01 { public static void main(String[] args) throws Exception { //1.创建服务器套接字对象 ServerSocket ss = new ServerSocket(8888); //让服务器一直运行 while (true) { //2.侦听并获取客户端套接字 Socket s = ss.accept(); //一张图片开启一个线程 new Thread(new Runnable() { @Override public void run() { try { //3.获取从通道中读取浏览器发送数据的字节输入 InputStream is = s.getInputStream(); // //4.将字节输入流转换为字符输入缓冲流 BufferedReader br = new BufferedReader(new InputStreamReader(is)); //5.读取第一行数据 GET /web/index.html HTTP/1.1 String line = br.readLine(); //6.将字符串变量line进行按照空格切割 String[] arr = line.split(" ");//{"GET","/web/index.html","HTTP/1.1"} //7.取出数组的第二个数据并去掉前面的/ // arr[1] 就是"/web/index.html" String path = arr[1].substring(1);//"web/index.html" // System.out.println("path = " + path); //8.根据浏览器访问服务器的资源路径创建字节输入流 //使用输入流关联该index.html页面读取到内存中 FileInputStream fis = new FileInputStream(path); //9.使用客户端套接字对象关联通道获取字节输出流 //将内存中的数据写到通道中 OutputStream os = s.getOutputStream(); //由于这里是想本地的内容响应给浏览器,那么浏览器接收数据之前需要一些特殊的信息(响应头) /* 响应头中包含响应的http协议版本HTTP/1.1 服务器返回的状态码 200 状态值:OK */ os.write("HTTP/1.1 200 OK\r\n".getBytes()); //Content-Type:text/html表示响应文本的类型 os.write("Content-Type:text/html\r\n".getBytes()); // 必须要写入空行,否则浏览器不解析 os.write("\r\n".getBytes()); //10.使用输入流读取index.html页面中的数据到内存中 byte[] buf = new byte[1024]; int len; while ((len = fis.read(buf)) != -1) { //向通道中写数据 os.write(buf, 0, len); } os.close(); fis.close(); br.close(); is.close(); s.close(); } catch (Exception e) { } } }).start(); } } }

    2.软件架构(理解)

    CS:Client Server 客户端 服务器端

    举例:

    QQ 爱奇艺 微信 迅雷 淘宝。。。。

    有点:

    ​ 1)客户端可以帮助服务器承载一些压力

    ​ 2)用户体验好一些,高清。。。不太卡

    缺点:

    ​ 1)用户按照一个客户端,升级麻烦,安装一些无关紧要的软件

    ​ 2)占用用户的空间

    ​ 3)维护起来不方便,成本大

    BS:Browser Server 浏览器 服务器

    举例:

    淘宝 京东 12306 唯品会。。。。

    ​ 优点:

    ​ 1)维护起来方便,只有服务器端,用户只需要安装一个浏览器即可,维护成本低

    ​ 2)不占用用户的空间,不用升级

    ​ 缺点:

    ​ 1)服务器压力大

    ​ 2)用户看视频不那么高清

    其实BS中也属于一种特殊cs

    3.JUnit单元测试(掌握)

    概念

    junit是单元测试,你想测哪个方法就写一个对应的测试方法,然后用junit运行。每个方法之间是独立的,非常灵活。而且测试方法一般不会直接写在原类中,而是单独的测试类,这样测试代码就完全与逻辑代码分开了。

    ​ Junit是Java语言编写单元测试框架。Junit属于第三方工具,一般情况下需要导入jar包,而多数Java开发环境都集成了Junit。

    使用方式

    1.使用之前的方式执行某个类的非静态方法

    package com.itheima.sh.junit_02; public class JunitDemo01 { public static void main(String[] args) { //创建对象 JunitDemo01 jd = new JunitDemo01(); jd.show(); } //定义非静态方法 public void show(){ System.out.println("show...."); } }

    2.使用junit方式执行非静态方法

    1.由于junit属于第三方的测试框架,使用之前需要导包,因为idea中已经集成了junit测试框架,我们在使用的时候直接导入包即可

    2.首先要测试运行的方法上书写一个测试注解

    @Test

    3.第一次使用由于没有导入包,所以会报错,在报错位置按alt+enter万能键就会导入包

    4.运行被@Test注解修饰的方法:

    在要运行的方法名上右键—run即可

    3.使用Junit测试框架运行某个方法的注意事项

    1.被测试的方法要求必须是public 修饰 无返回值 没有参数

    public void show(){ System.out.println("show...."); }

    2.被测试的方法所属类不要单独命名为Test因为会和Junit测试框架中名字冲突。建议类名定义规范:

    ​ ProductDaoTest ProductServiceTest xxxTest

    4.其他注解

    package com.itheima.sh.junit_02; import org.junit.*; /* 其他注解: 1.@Before : 只要运行一次测试方法就会在之前执行一次 2.@After: 只要运行一次测试方法就会在之后执行一次 3.@BeforeClass : 修饰静态方法,在运行测试方法之前执行,并且只执行一次 4.@AfterClass : 修饰静态方法,在运行测试方法之后执行,并且只执行一次 */ public class Junit01Test { @BeforeClass public static void beforeClass(){ System.out.println("beforeClass....."); } @AfterClass public static void afterClass(){ System.out.println("afterClass....."); } @Before public void before(){ System.out.println("before....."); } @After public void after(){ System.out.println("after....."); } //测试方法 @Test public void show1(){ System.out.println("show1...."); } @Test public void show2(){ System.out.println("show2...."); } } //beforeClass..... //before..... //show1.... //after..... //before..... //show2.... //after..... //afterClass.....

    小结:

    其他注解: 1.@Before : 只要运行一次测试方法就会在之前执行一次 2.@After: 只要运行一次测试方法就会在之后执行一次 3.@BeforeClass : 修饰静态方法,在运行测试方法之前执行,并且只执行一次 4.@AfterClass : 修饰静态方法,在运行测试方法之后执行,并且只执行一次

    断言技术

    1.作用:可以判断期望值和实际值是否相等,不相等则报错,相等则正常运行。

    2.使用方式:

    Assert.assertEquals(args1, args2); args1 :表示期望值 args2: 实际值

    3.代码演示

    package com.itheima.sh.junit_02; import org.junit.Assert; import org.junit.Test; /* 断言技术 */ public class Junit02Test { @Test public void show(){ //需求:调用方法求和值 int sum = getSum(10, 20); //使用断言技术断言和值是否正确 //10表示期望值 sum表示实际值 Assert.assertEquals(30,sum); } private int getSum(int a, int b) { return a*b; } }

    小结:

    断言技术:以判断期望值和实际值是否相等,不相等则报错,相等则正常运行。

    Assert.assertEquals(args1, args2); args1 :表示期望值 args2: 实际值

    4.NIO(掌握)

    1.概念介绍

    之前学习的IO称为BIO(blocking IO)具有阻塞功能。效率低。

    NIO:New IO 新的IO,从jdk1.4开始有的,也可以理解为Non-blocking IO 非阻塞的IO.提高效率。

    NIO包括三个组件:

    1.缓冲区(Buffer):专门用来存储数据的

    2.通道(Channel):连接客户端和服务器,该通道中只能传输Buffer

    3.选择器(Selector):使用选择器可以完成监听多个通道

    三者缺一不可。

    2.Java NIO 与 传统IO(BIO)的主要区别

    BIO:

    NIO:

    3.Buffer缓冲区(很重要)

    1.Buffer表示缓冲区,用来存储数据的,属于抽象类,我们一般使用子类

    2.子类:

    ByteBuffer(使用它) CharBuffer DoubleBuffer FloatBuffer IntBuffer LongBuffer ShortBuffer

    我们重点学习ByteBuffer

    1.ByteBuffer字节缓冲区。

    1.1获取ByteBuffer字节缓冲区的对象

    使用静态方法:

    1.static ByteBuffer allocate(int capacity) 分配一个新的字节缓冲区。 capacity 缓冲区的大小,就是字节数组大小。容量给定之后,不能变,底层是一个数组 2.static ByteBuffer allocateDirect(int capacity) 分配新的直接字节缓冲区 3.static ByteBuffer wrap(byte[] array)byte 数组包装到缓冲区中。 创建的缓冲区位于堆内存中,称为非直接缓冲区 说明: 1)allocate和wrap方法创建的缓冲区是位于堆内存中,称为间接缓冲区(非直接缓冲区) 2)allocateDirect方法创建的缓冲区位于不是jvm内存中,位于系统内存中,操作效率更高,何时读写数据以及释放资源我们无法控制,由系统控制。称为直接缓冲区

    补充方法:

    获取缓冲区容量大小:

    int capacity() 返回此缓冲区的容量。

    代码演示:

    package com.itheima.sh.buffer_03; import java.nio.ByteBuffer; /* 创建缓冲区方式: 1.static ByteBuffer allocate(int capacity) 分配一个新的字节缓冲区。 capacity 缓冲区的大小,就是字节数组大小。容量给定之后,不能变,底层是一个数组 2.static ByteBuffer allocateDirect(int capacity) 分配新的直接字节缓冲区 3.static ByteBuffer wrap(byte[] array) 将 byte 数组包装到缓冲区中。 创建的缓冲区位于堆内存中,称为非直接缓冲区 说明: 1)allocate方法创建的缓冲区是位于堆内存中,称为间接缓冲区(非直接缓冲区) 2)allocateDirect方法创建的缓冲区位于不是jvm内存中,位于系统内存中,操作效率更高,何时读写数据以及释放资源我们无法控制,由系统控制 称为直接缓冲区 */ public class BufferDemo01 { public static void main(String[] args) { //1.static ByteBuffer allocate(int capacity) 分配一个新的字节缓冲区。 ByteBuffer byteBuffer = ByteBuffer.allocate(10); //查看容量 int capacity() 返回此缓冲区的容量。 int capacity = byteBuffer.capacity(); System.out.println("capacity = " + capacity);//10 //2.static ByteBuffer allocateDirect(int capacity) 分配新的直接字节缓冲区 ByteBuffer byteBuffer1 = ByteBuffer.allocateDirect(10);//10 System.out.println(byteBuffer1.capacity()); //3.static ByteBuffer wrap(byte[] array) 将 byte 数组包装到缓冲区中。 创建的缓冲区位于堆内存中,称为非直接缓冲区 byte[] buf = {65,66,97}; ByteBuffer byteBuffer2 = ByteBuffer.wrap(buf); System.out.println(byteBuffer2.capacity());//3 } }

    非直接缓冲区

    直接缓冲区

    间接缓冲区的创建和销毁效率要高于直接缓冲区,但是间接缓冲区的工作效率要低于直接缓冲区

    1.2常用方法

    1.put array() int limit() capacity()

    package com.itheima.sh.buffer_03; import java.nio.ByteBuffer; import java.util.Arrays; /* 方法: 1.添加数据:abstract ByteBuffer put(byte b) 2.快速查看数据,将字节缓冲区变为字节数组: byte[] array() 3.int limit() :返回此缓冲区的限制。 4.Buffer limit(int newLimit) : 设置此缓冲区的限制.参数:newLimit表示指定的限制的索引,从limit开始后面的位置不能操作(包括newLimit索引对应的位置) 0=<limit<=capacity */ public class BufferDemo02 { public static void main(String[] args) { //1.创建非直接缓冲区 ByteBuffer byteBuffer = ByteBuffer.allocate(10); //2.添加数据 byteBuffer.put((byte) 11); byteBuffer.put((byte) 22); byteBuffer.put((byte) 33); //3. 快速查看数据,将字节缓冲区变为字节数组: byte[] array() byte[] arr = byteBuffer.array(); //获取容量 int capacity = byteBuffer.capacity(); //[11, 22, 33, 0, 0, 0, 0, 0, 0, 0] System.out.println(Arrays.toString(arr)); System.out.println("容量:"+capacity);//容量:10 //3.int limit() :返回此缓冲区的限制。 int limit = byteBuffer.limit();//默认的限制是和容量相等10 System.out.println("limit = " + limit); //4.Buffer limit(int newLimit) :设置的限制的索引以及该索引后面的空间都不能添加数据了 // byteBuffer.limit(5);//5索引以及后面的空间不能添加数据了 byteBuffer.put((byte) 44); byteBuffer.put((byte) 55); System.out.println(Arrays.toString(byteBuffer.array())); // byteBuffer.put((byte) 66); //更改limit byteBuffer.limit(0); byteBuffer.put((byte) 66); } }

    小结:

    1.添加数据:abstract ByteBuffer put(byte b) 2.快速查看数据,将字节缓冲区变为字节数组: byte[] array() 3.int limit() :返回此缓冲区的限制。 4.Buffer limit(int newLimit) : 设置此缓冲区的限制.参数:newLimit表示指定的限制的索引,从limit开始后面的位置不能操作(包括newLimit索引对应的位置) 0=<limit<=capacity

    2.position() :位置代表将要存放的元素的索引。位置不能小于0,也不能大于limit.

    int position() 返回此缓冲区的位置。 Buffer position(int newPosition) 设置此缓冲区的位置。 package com.itheima.sh.buffer_03; import java.nio.ByteBuffer; import java.util.Arrays; /* 1.position() :位置代表将要存放的元素的索引。位置不能小于0,也不能大于limit. */ public class BufferDemo03 { public static void main(String[] args) { //1.创建缓冲区 ByteBuffer byteBuffer = ByteBuffer.allocate(10); //position位置:0,限制limit:10,容量:10 System.out.println("position位置:"+byteBuffer.position()+",限制limit:"+byteBuffer.limit()+",容量:"+byteBuffer.capacity()); //2.添加数据 byteBuffer.put((byte) 11); //定义字节数组 byte[] buf = {22,33,44}; byteBuffer.put(buf); //position位置:4,限制limit:10,容量:10 System.out.println("position位置:"+byteBuffer.position()+",限制limit:"+byteBuffer.limit()+",容量:"+byteBuffer.capacity()); // position(int newPosition) 设置此缓冲区的位置。 byteBuffer.position(6); byteBuffer.put((byte) 55); //position位置:7,限制limit:10,容量:10 System.out.println("position位置:"+byteBuffer.position()+",限制limit:"+byteBuffer.limit()+",容量:"+byteBuffer.capacity()); //[11, 22, 33, 44, 0, 0, 55, 0, 0, 0] System.out.println(Arrays.toString(byteBuffer.array())); } }

    小结:

    position>=0 position <=limit

    每次添加数据都会向position位置添加,然后position向后移动

    图解:

    3.标记 (mark)与重置(reset) : 标记是一个索引,通过 Buffer 中的 mark() 方法指定 Buffer 中一个特定的 position,之后可以通过调用 reset() 方法恢复到这个 position标记。

    代码演示:

    package com.itheima.sh.buffer_03; import java.nio.ByteBuffer; import java.util.Arrays; /* 1.标记 (mark)与重置(reset) : 标记是一个索引,通过 Buffer 中的 mark() 方法指定 Buffer 中一个特定的 position,之后可以通过调用 reset() 方法恢复到这个 position标记。 */ public class BufferDemo04 { public static void main(String[] args) { //1.创建缓冲区 ByteBuffer byteBuffer = ByteBuffer.allocate(10); //position位置:0,限制limit:10,容量:10 System.out.println("position位置:"+byteBuffer.position()+",限制limit:"+byteBuffer.limit()+",容量:"+byteBuffer.capacity()); //2.添加数据 byteBuffer.put((byte) 11); //定义字节数组 byte[] buf = {22,33,44}; byteBuffer.put(buf); //position位置:4,限制limit:10,容量:10 System.out.println("position位置:"+byteBuffer.position()+",限制limit:"+byteBuffer.limit()+",容量:"+byteBuffer.capacity()); //记录当前position的位置是4 byteBuffer.mark(); //继续添加 byteBuffer.put((byte) 55); byteBuffer.put((byte) 66); //[11, 22, 33, 44, 55, 66, 0, 0, 0, 0] System.out.println(Arrays.toString(byteBuffer.array())); //position位置:6,限制limit:10,容量:10 System.out.println("position位置:"+byteBuffer.position()+",限制limit:"+byteBuffer.limit()+",容量:"+byteBuffer.capacity()); //重置,就是将当前的position恢复到mark的位置 byteBuffer.reset(); //在添加数据77 byteBuffer.put((byte) 77); //[11, 22, 33, 44, 77, 66, 0, 0, 0, 0] System.out.println(Arrays.toString(byteBuffer.array())); //position位置:5,限制limit:10,容量:10 System.out.println("position位置:"+byteBuffer.position()+",限制limit:"+byteBuffer.limit()+",容量:"+byteBuffer.capacity()); } }

    0 <= mark <= position <= limit <= capacity

    4.Buffer clear():还原缓冲区的状态。 清空缓冲区并返回对缓冲区的引用 数据没有被删除,数据还在缓冲区中。

    将position设置为:0将限制limit设置为容量capacity丢弃标记mark package com.itheima.sh.buffer_03; import java.nio.ByteBuffer; import java.util.Arrays; /* Buffer clear():还原缓冲区的状态。** **清空缓冲区并返回对缓冲区的引用** 数据没有被删除,数据还在缓冲区中。 - 将position设置为:0 - 将限制limit设置为容量capacity - 丢弃标记mark */ public class BufferDemo05 { public static void main(String[] args) { //创建缓冲区 ByteBuffer byteBuffer = ByteBuffer.allocate(10); //添加数据 byteBuffer.put((byte) 11); byteBuffer.put((byte) 22); byteBuffer.put((byte) 33); byteBuffer.put((byte) 44); //position位置:4,限制limit:10,容量:10 System.out.println("position位置:"+byteBuffer.position()+",限制limit:"+byteBuffer.limit()+",容量:"+byteBuffer.capacity()); //设置limit byteBuffer.limit(4); //添加数据 // byteBuffer.put((byte) 55); //position位置:4,限制limit:4,容量:10 System.out.println("position位置:"+byteBuffer.position()+",限制limit:"+byteBuffer.limit()+",容量:"+byteBuffer.capacity()); /* 调用clear方法: 1)将position变为0 2)limit变为capacity位置 3)清除标记 数据还在数组中 */ byteBuffer.clear(); //position位置:0,限制limit:10,容量:10 System.out.println("position位置:"+byteBuffer.position()+",限制limit:"+byteBuffer.limit()+",容量:"+byteBuffer.capacity()); //[11, 22, 33, 44, 0, 0, 0, 0, 0, 0] System.out.println(Arrays.toString(byteBuffer.array())); } }

    5.flip():缩小limit的范围。 切换。在读写数据之间要调用这个方法。

    将limit设置为当前position位置将当前position位置设置为0丢弃标记 package com.itheima.sh.buffer_03; import java.nio.ByteBuffer; import java.util.Arrays; /* flip():缩小limit的范围。 切换。在读写数据之间要调用这个方法。切换读取模式 - 将limit设置为当前position位置 - 将当前position位置设置为0 - 丢弃标记 */ public class BufferDemo06 { public static void main(String[] args) { //创建缓冲区 ByteBuffer byteBuffer = ByteBuffer.allocate(10); //添加数据 byteBuffer.put((byte) 11); byteBuffer.put((byte) 22); byteBuffer.put((byte) 33); byteBuffer.put((byte) 44); //position位置:4,限制limit:10,容量:10 System.out.println("position位置:"+byteBuffer.position()+",限制limit:"+byteBuffer.limit()+",容量:"+byteBuffer.capacity()); //调用 flip():方法开始读取数据 byteBuffer.flip(); //position位置:0,限制limit:4,容量:10 System.out.println("position位置:"+byteBuffer.position()+",限制limit:"+byteBuffer.limit()+",容量:"+byteBuffer.capacity()); } }

    图解:

    小结:

    flip():缩小limit的范围。 切换。在读写数据之间要调用这个方法。切换读取模式

    ​ 将limit设置为当前position位置 ​ 前position位置设置为0

    ​ 丢弃标记

    6.**获取Buffer中的数据: **

    abstract byte get() 读取单个字节。读取此缓冲区当前位置的字节,然后该位置position递增。 ByteBuffer get(byte[] dst)批量读取多个字节到 dst 中,position移动到最后.需要定义一个空的字节数组 abstract byte get(int index)读取指定索引位置的字节(不会移动 position)

    代码演示:

    package com.itheima.sh.buffer_03; import java.nio.ByteBuffer; import java.util.Arrays; /* 获取数据方法: abstract byte get() 读取单个字节。读取此缓冲区当前位置的字节,然后该位置position递增。 ByteBuffer get(byte[] dst)批量读取多个字节到 dst 中,position移动到最后.需要定义一个空的字节数组 abstract byte get(int index)读取指定索引位置的字节(不会移动 position) */ public class BufferDemo07 { public static void main(String[] args) { //创建缓冲区 ByteBuffer byteBuffer = ByteBuffer.allocate(10); //添加数据 byteBuffer.put((byte) 11); byteBuffer.put((byte) 22); byteBuffer.put((byte) 33); byteBuffer.put((byte) 44); //切换为读取数据模式 byteBuffer.flip(); // abstract byte get() 读取单个字节。读取此缓冲区当前位置的字节,然后该位置position递增。 /* byte b = byteBuffer.get(); System.out.println("b = " + b);*/ //使用循环控制读取数据 byteBuffer.limit() 就是4 /*for(int i=0;i<byteBuffer.limit();i++){//i表示控制次数 byte b = byteBuffer.get(); System.out.println("b = " + b); }*/ // ByteBuffer get(byte[] dst)批量读取多个字节到 dst 中,position移动到最后.需要定义一个空的字节数组 // byte[] buf = new byte[byteBuffer.limit()];//长度是到limit这里就是4 // byteBuffer.get(buf);//该方法结束将数据放到数组中 // //[11, 22, 33, 44] // System.out.println(Arrays.toString(buf)); //abstract byte get(int index)读取指定索引位置的字节(不会移动 position) for(int index=0;index<byteBuffer.limit();index++){//index表示索引 byte b = byteBuffer.get(index); System.out.println("b = " + b); } } }

    小结:

    获取数据方法:

    abstract byte get() 读取单个字节。读取此缓冲区当前位置的字节,然后该位置position递增。 ByteBuffer get(byte[] dst)批量读取多个字节到 dst 中,position移动到最后.需要定义一个空的字节数组 abstract byte get(int index)读取指定索引位置的字节(不会移动 position)

    4.Channel通道(很重要)

    1.概念

    通过channel通道对持久设备和内存建立连接,思想类似于之前学习的BIO.但是通道不能直接传输数据,只是负责建立通道,传输数据必须存储到Buffer中,然后传递buffer缓冲区。channel属于双向的,可以读写都位于一个通道中。

    2.分类

    FileChannel:是操作本地文件的通道

    SocketChannel:相当于之前BIO对应的Socket表示客户端通道

    ServerSocketChannel:相当于之前BIBO对应的ServerSocket表示服务器端通道

    DatagramChannel:UDP协议

    3.获取通道

    1.FileChannel:是操作本地文件的通道

    ​  FileInputStream : 获取的是FileChannel通道

     FileOutputStream:获取的是FileChannel通道

     RandomAccessFile:获取的是FileChannel通道

    ​ RandomAccessFile表示随机访问的文件类,可以指定操作模式:

    RandomAccessFile(String name, String mode) 参数: name:操作文件的路径 mode:操作文件的模式: "r" 读模式 "rw" 读写模式

    分别使用上述三个类中的**FileChannel getChannel()**方法就可以获取 FileChannel 通道

    4.FileChannel 的使用

    代码演示:

    package com.itheima.sh.channel_04; import java.io.FileInputStream; import java.io.FileOutputStream; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; /* FileChannel讲解: 使用步骤: 1)使用FileInputStream对象调用FileChannel getChannel() 获取输入的 FileChannel 2)使用FileOutputStream对象调用 FileChannel getChannel() 获取输出的 FileChannel 需求:使用FileChannel将D:\test\故事.txt复制到项目根目录下为故事.txt 说明:源文件故事.txt文件大小是134字节 */ public class ChannelDemo01 { public static void main(String[] args) throws Exception{ //1.创建字节输入流关联数据源文件 D:\test\故事.txt FileInputStream fis = new FileInputStream("D:\\test\\故事.txt"); //2.创建字节输出流对象关联目的地文件 目录下为故事.txt FileOutputStream fos = new FileOutputStream("故事.txt"); //3.分别获取通道即FileChannel getChannel() //3.1获取读取数据的通道 FileChannel inChannel = fis.getChannel(); //3.2获取读写数据的通道 FileChannel outChannel = fos.getChannel(); //4.创建字节缓冲区ByteBuffer ByteBuffer buffer = ByteBuffer.allocate(1024); //5.使用FileChannel对象调用FileChannel类中的读取数据方法放到缓冲区中 //abstract int read(ByteBuffer dst) while((inChannel.read(buffer))!=-1){ //切换读取模式 buffer.flip(); //6.使用FileChannel类中的写方法将缓冲区的数据写到目的地文件中 //abstract int write(ByteBuffer src) outChannel.write(buffer); //清空 buffer.clear(); } //7.关闭资源 outChannel.close(); inChannel.close(); fos.close(); fis.close(); } }

    小结:

    1)使用FileInputStream对象调用FileChannel getChannel() 获取输入的 FileChannel 2)使用FileOutputStream对象调用 FileChannel getChannel() 获取输出的 FileChannel

    5.FileChannel结合MappedByteBuffer实现高效读写

    1.MappedByteBuffer 属于ByteBuffer 子类,创建的缓冲区称为直接缓冲区,位于系统内存中,操作效率要高很多。

    需求:将D:\test\故事.txt赋值到项目根目录

    代码演示:

    package com.itheima.sh.channel_04; import java.io.RandomAccessFile; import java.nio.MappedByteBuffer; import java.nio.channels.FileChannel; /* FileChannel结合MappedByteBuffer实现高效读写 使用步骤: 1.获取FileChannel通道 使用:随机操作文件的类使用:RandomAccessFile(String name, String mode) 2.使用通道对象调用FileChannel中的映射方法获取MappedByteBuffer abstract MappedByteBuffer map(FileChannel.MapMode mode, long position, long size) 将此通道的文件区域直接映射到内存中。 mode:表示映射模式: static FileChannel.MapMode READ_ONLY 只读映射模式。 static FileChannel.MapMode READ_WRITE 读取/写入映射模式。 position:表示开始操作的位置 size:要映射的区域大小,我们可以使用FileChannel中的方法获取: abstract long size() 返回此通道的文件的当前大小。 返回值: MappedByteBuffer的父类是ByteBuffer,那么MappedByteBuffer的对象可以使用ByteBuffer方法 */ public class ChannelDemo02 { public static void main(String[] args) throws Exception{ //1.创建随机访问文件的类的对象 RandomAccessFile read = new RandomAccessFile("D:\\test\\故事.txt", "r");//r读模式 RandomAccessFile write = new RandomAccessFile("故事.txt", "rw");//rw是读写模式 //2.获取FileChannel通道 FileChannel inChannel = read.getChannel(); FileChannel outChannel = write.getChannel(); //abstract long size() 返回此通道的文件的当前大小。 long size = inChannel.size(); //3.获取MappedByteBuffer缓冲区 // abstract MappedByteBuffer map(FileChannel.MapMode mode, long position, long size) MappedByteBuffer inMap = inChannel.map(FileChannel.MapMode.READ_ONLY, 0, size); MappedByteBuffer outMap = outChannel.map(FileChannel.MapMode.READ_WRITE, 0, size); for(int i=0;i<size;i++){ //获取数据 byte b = inMap.get(); //放到outMap outMap.put(b); } outChannel.close(); inChannel.close(); write.close(); read.close(); } }

    小结;只能操作2G以下的

    Processed: 0.011, SQL: 9