天天看點

java socket與io流_java基礎知識——網絡程式設計、IO流

IO流

位元組流:處理位元組資料的流對象,計算機中最小資料單元就是位元組。InputStream OutputStream

字元流:字元編碼問題,将位元組流和編碼表封裝成對象就是字元流。Reader Write

讀、寫都會發生 IO 異常。io 異常的處理方式 :io 一定要寫 finally。fw.flush();//重新整理緩沖區,fw.close();//關閉流。

IO 中的使用到了一個設計模式: 裝飾設計模式。

裝飾設計模式解決:對一組類進行功能的增強。

包裝:寫一個類(包裝類)對被包裝對象進行包裝;

* 1、包裝類和被包裝對象要實作同樣的接口;

* 2、包裝類要持有一個被包裝對象;

* 3、包裝類在實作接口時,大部分方法是靠調用被包裝對象來實作的,對于需要修改的方法我們自己實作;

字元流

Reader : 用于讀取字元流的抽象類。子類必須實作的方法隻有 read(char[], int, int) 和 close()。

Writer : 寫入字元流的抽象類。子類必須實作的方法僅有 write(char[], int, int)、flush() 和 close()。

位元組流

InputStream、OutputStream

BufferedWriter :是給字元輸出流提高效率用的,那就意味着,緩沖區對象建立時,必須要先有流對象。明

确要提高具體的流對象的效率。

FileWriter fw = new FileWriter("bufdemo.txt");

BufferedWriter bufw = new BufferedWriter(fw); // 讓緩沖區和指定流相關聯。

for(int x=0; x<4; x++){

bufw.write(x+"abc");

bufw.newLine(); // 寫入一個換行符,這個換行符可以依據平台的不同寫入不同的換行符。

bufw.flush();//對緩沖區進行重新整理,可以讓資料到目的地中。

}

bufw.close(); // 關閉緩沖區,其實就是在關閉具體的流。

-----------------------------

BufferedReader :

FileReader fr = new FileReader("bufdemo.txt");

BufferedReader bufr = new BufferedReader(fr);

String line = null;

while((line=bufr.readLine())!=null){ e //readLine 方法傳回的時候是不帶換行符的。

System.out.println(line);

}

bufr.close();

-----------------------------

//記住,隻要一讀取鍵盤錄入,就用這句話。

BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));

BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));//輸出到控制台

String line = null;

while((line=bufr.readLine())!=null){

if("over".equals(line))

break;

51 / 65

bufw.write(line.toUpperCase());//将輸入的字元轉成大寫字元輸出

bufw.newLine();

bufw.flush();

}

bufw.close();

bufr.close();

流的操作規律:

1 ,明确源和目的。

資料源:就是需要讀取,可以使用兩個體系:InputStream、Reader;

資料彙:就是需要寫入,可以使用兩個體系:OutputStream、Writer;

2 ,操作的資料是否是純文字資料?

如果是:資料源:Reader

資料彙:Writer

如果不是:資料源:InputStream

資料彙:OutputStream

3 ,雖然确定了一個體系,但是該體系中有太多的對象,到底用哪個呢?

明确操作的資料裝置。

資料源對應的裝置:硬碟(File),記憶體(數組),鍵盤(System.in)

資料彙對應的裝置:硬碟(File),記憶體(數組),控制台(System.out)。

4 ,需要在基本操作上附加其他功能嗎?比如緩沖。

如果需要就進行裝飾。

File類

将檔案系統中的檔案和檔案夾封裝成了對象。提供了更多的屬性和行為可以對這些檔案和檔案夾

進行操作。這些是流對象辦不到的,因為流隻操作資料。

createNewFile() 、mkdir()、getAbsolutePath()

遞歸

使用情況:功能内部又用到該功能,但是傳遞的參數值不确定。

遞歸的注意事項:

1:一定要定義遞歸的條件。

2:遞歸的次數不要過多。容易出現 StackOverflowError 棧記憶體溢出 錯誤。

其實遞歸就是在棧記憶體中不斷的加載同一個函數。

Java遞歸算法的小例子 求1+2+3…+1000 和

public class Test1 {

int sum=0;

int a=1;

public void sum()

{

sum+=a;

a++;

if(a<=1000)

{

sum();//調用自身實作遞歸

}

}

public static void main(String[] args) {

Test1 test=new Test1();

test.sum();

System.out.println("計算結果:"+test.sum+"!");

}

擴充功能的流對象

PrintStream : 列印流

PrintStream m 可以操作目的:1:File 對象。2:字元串路徑。3:位元組輸出流。

PrintWriter :該對象的目的地有四個:1:File 對象。2:字元串路徑。3:位元組輸出流。4:字元輸出流。

PrintWriter out = new PrintWriter( new FileWriter(“out.txt”), true);//設定 true 後自動重新整理

System.in,System.out 這兩個标準的輸入輸出流,在 jvm 啟動時已經存在了。随時可以使用。當

jvm 結束了,這兩個流就結束了。但是,當使用了顯示的 close 方法關閉時,這兩個流在提前結束了。

SequenceInputStream : 序列流

作用就是将多個讀取流合并成一個讀取流實作資料合并。

合并原理:多個讀取流對應一個輸出流。

切割原理:一個讀取流對應多個輸出流。

管道流

管道讀取流和管道寫入流可以像管道一樣對接上,管道讀取流就可以讀取管道寫入流寫入的資料。

注意 :需要加入多線程技術,因為單線程,先執行 read,會發生死鎖,因為 read 方法是阻塞式的,沒有資料的

read 方法會讓線程等待。

public static void main(String[] args) throws IOException{

PipedInputStream pipin = new PipedInputStream();

PipedOutputStream pipout = new PipedOutputStream();

pipin.connect(pipout);

new Thread(new Input(pipin)).start();

new Thread(new Output(pipout)).start();

}

對象序列化

靜态資料不能被序列化,因為靜态資料不在堆記憶體中;用transient關鍵字修飾變量,可以将非靜态資料不進行序列化。

Serializable :用于啟動對象的序列化功能,可以強制讓指定類具備序列化功能,該接口中沒有成員,這是一

個标記接口。

ByteArrayInputStream : 源 : 記憶體

ByteArrayOutputStream :目的:記憶體。

這兩個流對象不涉及底層資源調用,操作的都是記憶體中數組,是以不需要關閉。

網絡程式設計

端口:0-65535

//通過名稱(ip 字元串 or 主機名)來擷取一個 ip 對象。

InetAddress ip = InetAddress.getByName("www.baidu.com");//java.net.UnknownHostException

socket

為網絡服務提供的一種機制,通信的兩端都有 Socket,網絡通信其實就是 Socket 間的通信,資料在兩個

Socket 間通過 IO 傳輸。

udp傳輸

資料一定要封裝到資料包中,資料包中包括目的位址、端口、資料等資訊。将 udp 封裝成對象,易于我們的使用,這個對象就是 DatagramSocket

發送端:

1,建立 udp 的 socket 服務,建立對象時如果沒有明确端口,系統會自動配置設定一個未被使用的端口。

2,明确要發送的具體資料。

3,将資料封裝成了資料包。

4,用 socket 服務的 send 方法将資料包發送出去。

5,關閉資源。

import java.net.*;

class UdpSend{

public static void main(String[] args)throws Exception {

// 1 1 ,建立 p udp 的 的 t socket 服務。

DatagramSocket ds = new DatagramSocket(8888);//指定發送端口,不指定系統會随機配置設定。

// 2 2 ,明确要發送的具體資料。

String text = "udp 傳輸示範 哥們來了";

byte[] buf = text.getBytes();

// 3 3 ,将資料封裝成了資料包。

DatagramPacket dp = new DatagramPacket(buf,

buf.length,InetAddress.getByName("10.1.31.127"),10000);

// 4 4 ,用 t socket 服務的 d send 方法将資料包發送出去。

ds.send(dp);

// 5 5 ,關閉資源。

ds.close();

}

}

p udp 的接收端:

1,建立 udp 的 socket 服務,必須要明确一個端口,作用在于,隻有發送到這個端口的資料才是這個接收端可

以處理的資料。

2,定義資料包,用于存儲接收到資料。

3,通過 socket 服務的接收方法将收到的資料存儲到資料包中。

4,通過資料包的方法擷取資料包中的具體資料内容,比如 ip、端口、資料等等。

5,關閉資源。

class UdpRece {

public static void main(String[] args) throws Exception{

// 1 1 ,建立 p udp 的 的 t socket 服務。

DatagramSocket ds = new DatagramSocket(10000);

// 2 2 ,定義資料包,用于存儲接收到資料。先定義位元組數組,資料包會把資料存儲到位元組數組中。

byte[] buf = new byte[1024];

DatagramPacket dp = new DatagramPacket(buf,buf.length);

// 3 3 ,通過 t socket 服務的接收方法将收到的資料存儲到資料包中。

ds.receive(dp);//該方法是阻塞式方法。

// 4 4 ,通過資料包的方法擷取資料包中的具體資料内容,比如 ip ,端口,資料等等。

String ip = dp.getAddress().getHostAddress();

int port = dp.getPort();

String text = new String(dp.getData(),0,dp.getLength());//将位元組數組中的有效部分轉成字元串。

System.out.println(ip+":"+port+"--"+text);

// 5 5 ,關閉資源。

ds.close();

}

}

tcp傳輸

兩個端點的建立連接配接後會有一個傳輸資料的通道,這通道稱為流,而且是建立在網絡基礎上的流,

稱之為 socket 流。該流中既有讀取,也有寫入。

TCP 用戶端 :

1,建立 tcp 的 socket 服務,最好明确具體的位址和端口。這個對象在建立時,就已經可以對指定 ip 和端口

進行連接配接(三次握手)。

2,如果連接配接成功,就意味着通道建立了,socket 流就已經産生了。隻要擷取到 socket 流中的讀取流和寫入

流即可,隻要通過 getInputStream 和 getOutputStream 就可以擷取兩個流對象。

3,關閉資源。

import java.net.*;

import java.io.*;

//需求:用戶端給伺服器端發送一個資料。

class TcpClient{

public static void main(String[] args) throws Exception{

Socket s = new Socket("10.1.31.69",10002);

OutputStream out = s.getOutputStream();// 擷取了 t socket 流中的輸出流對象。

out.write("tcp 示範,哥們又來了!".getBytes());

s.close();

}

}

TCP 服務端:

1,建立服務端 socket 服務,并監聽一個端口。

2,服務端為了給用戶端提供服務,擷取用戶端的内容,可以通過 accept 方法擷取連接配接過來的用戶端對象。

3,可以通過擷取到的 socket 對象中的 socket 流和具體的用戶端進行通訊。

4,如果通訊結束,關閉資源。注意:要先關用戶端,再關服務端。

class TcpServer{

public static void main(String[] args) throws Exception{

62 / 65

ServerSocket ss = new ServerSocket(10002);//建立服務端的 socket 服務

Socket s = ss.accept();//擷取用戶端對象

String ip = s.getInetAddress().getHostAddress();

System.out.println(ip+".....connected");

// 可以通過擷取到的 socket 對象中的 socket 流和具體的用戶端進行通訊。

InputStream in = s.getInputStream();//讀取用戶端的資料,使用用戶端對象的 socket 讀取流

byte[] buf = new byte[1024];

int len = in.read(buf);

String text = new String(buf,0,len);

System.out.println(text);

// 如果通訊結束,關閉資源。 注意:要先關用戶端,在關服務端。

s.close();

ss.close();

}

}

反射技術

反射技術可以對一個類進行解剖。

基本步驟:

1 、 獲得 s Class 對象 ,就是擷取到指定的名稱的位元組碼檔案對象 。

2 、 執行個體化對象, 獲得類的屬性、方法或構造函數。

3、通路屬性、調用方法、調用構造函數建立對象

正規表達式

常見操作:

1,比對:其實用的就是 String 類中的 matches 方法。

String reg = “[1-9][0-9]{4,14}”;

boolean b = qq. matches(reg);//将正則和字元串關聯對字元串進行比對。

2,切割:其實用的就是 String 類中的 split 方法。

3,替換:其實用的就是 String 類中的 replaceAll();

4,擷取:

1),先要将正規表達式編譯成正則對象。使用的是 Pattern 中靜态方法 compile(regex);

2),通過 Pattern 對象擷取 Matcher 對象。

Pattern 用于描述正規表達式,可以對正規表達式進行解析。

而将規則操作字元串,需要從新封裝到比對器對象 Matcher 中。

然後使用 Matcher 對象的方法來操作字元串。

如何擷取比對器對象呢?

通過 Pattern 對象中的 matcher 方法。該方法可以正則規則和字元串想關聯。并傳回比對器對象。

3),使用 Matcher 對象中的方法即可對字元串進行各種正則操作。