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以下的