首頁 >Java >java教程 >菜鳥初學Java的備忘錄(五)

菜鳥初學Java的備忘錄(五)

黄舟
黄舟原創
2016-12-20 13:49:451173瀏覽


對幾個java的基礎知識作一下補充。

一.異常
Java對異常的處理同Delphi一樣,不是刻意的去避免它的發生,而是等它發生後去補救.
Delphi的異常處理簡單來說就是一下語句

Try
Except/ /異常發生後就轉入此處執行
Finally//不管異常發不發生,都轉入此處運行
End

與此相類似,Java的異常處理的基本形式如下
try{
}catch( ExceptionType1 e){
file://對異常情況1的處理
}catch(ExceptionType2 e){
file://對異常情況2的處理
throw(e)//拋出異常,和Delphi中的raise是一回事
}

要補充的是,對大多數的異常,假如你要在正常運行的程序中而不是捕捉異常的程序中明確的拋出,Java的編譯器需要你事先對你要拋出的異常作聲明,否則不答應編譯通過.這個任務是由throws來完成的.

二.Java的輸入輸出流
2.1 輸出
System.out.PRint file://這裡out是一個靜態方法喔
System.out.println
System.err.print file://err和out一樣也是標準輸出,至於有什麼不同,我目前還不清楚
System.err.println
2.2 輸入
System.in.read ()
2.3 檔案的操作
只需要幾個註解的例子就可以了。
第一個是一個顯示檔案基本資訊的程式

import java.io.*;//調入和io相關的類別
class fileinfo{
file://注重,main函數一定是靜態方法

public static void main(String args[])throws IOException{
File fileToCheck;//使用檔案物件建立實例
if (args.length>0){
for (int i=0;ifileToCheck=new File(args[i]);//為檔案物件分配空間
info(fileToCheck);//這裡所引用的info一定要是靜態方法成員
}
}
else{
System.out.println( "no file given");
}
}

public static void info(File f)throws IOException{
System.out.println("Name:"+f.getName());
System.out.println("Name:"+f.getName());
System.out.println( "Path:"+f.getPath());
if (f.exists()){
System.out.println("File exists.");
System.out.print((f.canRead()? " and is Readable":""));//判定函數,假如滿足條件,輸出前者,否則輸出後者
System.out.print((f.canWrite()?"and is Writable":"") );
System.out.print(".");
System.out.println("File is"+f.length()+"bytes.");
}
else{
System.out.println( "File does not exist.");
}
}
}

第二個例子是一個儲存電話資訊的小程式,使用者輸入姓名和電話號碼,程式將其存入phone.numbers檔案中,透過FileOutputStream來實作

import java.io.*;

class phones{
static FileOutputStream fos;
public static final int lineLength=81;
public static void main(String ints[ new byte[lineLength];
byte[] name=new byte[lineLength];
int i;
fos=new FileOutputStream("phone.numbers");
while(true){
System.err.println("Enter a name(enter ′done′ to quit)");
readLine(name);
if ("done".equalsIgnoreCase(new String(name,0,0,4))){
break;
}
System. err.println("Enter the phone number");
readLine(phone);
for (i=0;phone[i]!=0;i++){
fos.write(phone[i]);
}
fos.write(′,′);
for (i=0;name[i]!=0;i++){
fos.write(name[i]);
}
fos.write(′ ′);
}
fos.close();
}

private static void readLine(byte line[])throws IOException{
int i=0,b=0;
while((iline[i++]=(byte)b;
}
line[i]=(byte)(0);
}
}

2.4流
無非是兩種
輸出流,讓我們來寫的
輸入流,給我們來讀的
java.io包中有很多種類的輸入輸出流
1.FileInputStream和FileOutputStream 節點流
2.BufferedInputStream和BufferedOutputStream 過濾流
3.DataInputStream和DataOutputStream 增強的過濾流
4.PipedInputStream和PipledOutputStream 用於線程的流

昨天講了流的概念,昨天關於Sockets的學習了.昨天我已經講了的作用.

現在,我們將創建一個簡單的通訊程式,以獲得對Socket的實質性的熟悉.該程式包括兩個部分,客戶機(RemoteFileClient)和伺服器(RemoteFileServer).客戶機向伺服器發出請求,要求讀取伺服器上的檔案資訊.伺服器將回應請求,將對應的檔案資訊傳給客戶機,將對應的檔案資料傳給客戶機.

首先我們建立RemoteFileClient類別:
import java.io.*;/ /java.io 套件提供對流進行讀寫的工具,也是與TCP 套接字通訊的唯一途徑
import java.net.*;//java.net 套件提供套接字工具。

public class RemoteFileClient {
protected String hostIp;
protected int hostPort;
protected BufferedReader socketReader;//負責讀取資料的物件
protected PrintWriter socketWriter;//負責寫入資料的物件

file://類別的建構器有兩個參數:遠端主機的IP 位址(hostIp)和連接埠號碼( hostPort)各一個.建構器將它們賦給實例變數
public RemoteFileClient(String aHostIp, int aHostPort) {
hostIp = aHostIp;
hostPort = aHostPort;
}
static void
hostPort = aHostPort;
}

file://連接到遠端伺服器
public void setUpConnection() {
}
file://向遠端伺服器請求檔案資訊
public String getFile(String fileNameToGet) {
}
file://從遠端伺服器上斷開啟
public void tearDownConnection() {
}
}

首先來實作main()
public static void main(String[] args) {
RemoteFileClient remoteFileClient = new RemoteFileClient"127.00127.為了方便調試,我們把本機伺服器當作遠端伺服器
remoteFileClient.setUpConnection();//連線。不能直接使用setUpConnection,因為它是非靜態變量,需要建立實例後,對實例進行引用,可以看我第一天的日記,上面寫的非常具體
String fileContents =
remoteFileClient.getFile("RemoteFile.txt") ;//讀取

remoteFileClient.tearDownConnection();//斷開

System.out.println(fileContents);//輸出讀取內容
}

步驟非常清楚.那麼我們分別看連接,/輸出讀取內容
}

步驟非常清楚.那麼我們分別看連接, ,斷開是怎麼實現的
1.連線
public void setUpConnection() {
try {
Socket client = new Socket(hostIp, hostPort);//建立Socket物件

InputStream inFromServerStream=client.getInputStream();
socketReader = new BufferedReader(new InputStreamReader(inFromServerStream));
file://把Socket的InputStream包裝進BufferedReader 以使我們能夠讀取流的行詞outToServerStream);
file://把Socket的OutputStream包裝進PrintWriter 以使我們能夠發送檔案請求到伺服器

} catch (UnknownHostException e) {
System.out.println("Error setting Exception e) {
System.out.println("Error setting Exception e) {
System.out.println("Error setting Exception e) {nectionnection up " + hostIp + ":" + hostPort);
file://對Socket物件建立錯誤的例外處理
} catch (IOException e) {
System.out.println("Error setting up socket connection: " + e) ;
file://對IO錯誤的異常處理
}
}

2.讀取
public String getFile(String fileNameToGet) {
StringBuffer fileLines = new StringBuffer();/StringBuffer物件也是它更靈活,這裡是用來存放讀取內容的

try {
socketWriter.println(fileNameToGet);
socketWriter.flush();//檔案存放位址輸出到socketWriter中,然後清空緩衝區,讓這個位址送到伺服器中去

String line = null;
while ((line = socketReader.readLine()) != null)
fileLines.append(line + " ");現在已經送到伺服器去了,那我們都要等待回應,這裡的程式就是等待伺服器把我們所需要的檔案內容傳過來
} catch (IOException e) {
System.out.println("Error reading from file: " + fileNameToGet);
}

return fileLines.toString();//別忘了把buffer中的內容轉成String再回傳
}

3.斷開
public void tearDown() {
try {
sock ;
socketReader.close();
} catch (IOException e) {
System.out.println("Error tearing down socket connection: " + e);
}
}

tearDownConnection() Socket 的InputStream 和OutputStream 上建立的BufferedReader 和PrintWriter。這樣做會關閉我們從Socket 獲取的底層流,所以我們必須捕捉可能的IOException

好,現在可以總結一下客戶機程序的創建步驟了
1.用要連接的機器的IP端口號實例化Socket(如有問題則拋出Exception)。
2.取得Socket 上的流以進行讀寫.
3.把流包裝進BufferedReader/PrintWriter 的實例.
4.對Socket 進行讀寫.具體說來,就是在Writer上傳送文件地址信息給服務器,在Reader上讀取伺服器傳來的檔案資訊
5.關閉開啟的流。

下面是RemoteFileClient 的程式碼清單

import java.io.*;
import java.net.*;

public class RemoteFileClient {
protected BufferedRead socketReattecader socerform;
protected int hostPort ;

public RemoteFileClient(String aHostIp, int aHostPort) {
hostIp = aHostIp;
hostPort = aHostPort;
}
public String getFile(String fileNameToet) { ter. println(fileNameToGet);
socketWriter.flush();

String line = null;
while ((line = socketReader.readLine()) != null)
fileLines.append(line + " ");
} catch (IOException e) {
System.out.println("讀取檔案時發生錯誤:" + fileNameToGet);
}

return fileLines.toString();
public static void main(String[] args) {
RemoteFileClient remoteFileClient = new RemoteFileClient("127.0.0.1", 3000);
remoteFileClient.setUpConnection();
RemoteFileClient.tearDownConnection();

System.out.println(fileContents);
}
public void setUpConnection() {
try {
Socket client =Out new Socket(StreamStreamI, ( );
InputStream inFromServerStream=client.getInputStream();
socketReader = new BufferedReader(new InputStreamReader(inFromServerStream));
socketWriter = new PrintWriter(outServerStream));
socketWriter = new PrintWriter(outServerStream); ln ( "設定套接字連線時發生錯誤:未知主機位於" + hostIp + ":" + hostPort);
} catch (IOException e) {
System.out.println("設定套接字連線時發生錯誤:" + e);
}
}
public void TeaDownConnection() {
try {
socketWriter.close();
socketReader.close();
} catch (IOException e) {
System。字連線時發生錯誤:" + e);
}
}
}

好了,現在看看伺服器端的程式怎麼建立寫。
RemoteClientServer類別:
import java.io.*;
import java.net.*;

public class RemoteFileServer {
protected int ListenPort = 3000;publicoid publicstatic v receiveConnections() {
}
public void handleConnection(SocketcomingConnection) {
}
}

跟監聽中一樣,先導入java.net 的java.io。接著,給我們的類別一個實例變數以保存端口,我們從該端口偵聽進入的連接。部分情況下,連接埠是 3000。
acceptConnections()將答應客戶機到連接伺服器
handleConnection()負責與負載 Socket 互動以將您所要求的文件的內容傳送到負載。

首先看main()

public static void main(String[] args) {
RemoteFileServer server = new RemoteFileServer();
server.acceptConnections();
}
就是讓函式進入主機無聽狀態,所以直接呼叫acceptConnection()。要注意的是,必須先建立RemoteFileServer()的實例,而不是直接呼叫。

那麼伺服器是怎麼透過acceptConnection()來監聽前置的連線呢?而且如果兼聽了,又怎麼處理呢?我們來看
public void receiveConnections() {
try {
ServerSocket server = new ServerSocket(listenPort);//同客戶端的Socket對應,在伺服器端,我們需要ServerSocket對象,參數是兼聽的連接埠號碼
Socket傳入Connection = null;//建立一個客戶端的Socket變量,以接收從客戶監聽到的Socket
while (true) {
incomingConnection = server.accept();//該呼叫ServerSocket的accept()來告訴它開始偵聽,
handleConnection(incomingConnection);
}
file: //不斷監聽直到有了一個連接請求,然後交由handleConnection處理
} catch (BindException e) {
System.out.println("無法綁定到連接埠" + ListenPort);
} catch (IOException e) {
System.out.println("Unable to instantiate a ServerSocket on port: " + ListenPort);
}
}

無論如果何時創建了一個無法做到何時綁定到指定連接埠(可能是因為其他什麼控制了該)連接埠)的ServerSocket,Java程式碼都會拋出一個錯誤。所以這裡我們必須捕獲可能的BindException。同時,就像在發起端上時一樣,我們必須捕獲IOException,當我們嘗試在ServerSocket上接受連接時,它可以通過用幾千個調用setSoTimeout()來為accept()調用設置超時,坐標實際長時間的等待。呼叫setSoTimeout()呼叫accept()經過指定佔用時間後觸發IOException

最要害的處理在handleConnection()中,現在已經連接到了客戶端的Socket,要從該Socket中讀取客戶端的請求和回應。

public void handleConnection(SocketcomingConnection) {
try {
OutputStream outputToSocket =傳入Connection.getOutputStream();
InputStream inputFromSocket =傳入Connection.getInputStream();

file://首先獲取同Socket相關聯的流outputToSocket和InputStream
file://其中outputToSocket是要回傳給客戶端Socket的流
file://InputStream是客戶端發來的請求,這裡就是文件路徑,即"RemoteFile.txt"

BufferedReader streamReader,即"RemoteFile.txt"

BufferedReader streamReader new BufferedReader(new InputStreamReader(inputFromSocket));

file://首先代表InputStream轉換到BufferedReader中

FileReader fileReader = new FileReader(new File(streamReader.readLine()));
file://從BufferedReader中讀出檔案路徑,建立新物件FileReader

BufferedReader bufferedFileReader = new BufferedReader

BufferedReader bufferedFileReader = new BufferedReader(fileReader); /再次建立BufferedReader對象,這次它讀取獲取是文件裡面的內容

PrintWriter streamWriter =
new PrintWriter(OutputStream);

file://把Socket的outputToSocket流到PrintWriter 包裝到客戶端

String line = null;
while ((line = bufferedFileReader.readLine()) != null) {
streamWriter.println(line);
}
file://從bufferedFileReader.經由streamWriter輸出到客戶端

fileReader.close();
streamWriter.close();//注重Socket的兩個流關閉的順序
streamReader.close();
file://完成之後關閉所有流

} catch (Exception e) {
System.out.println("Error handling a client: " + e);
}
}

請注重完成所有操作之後關閉流的順序,streamWriter的關閉在streamReader的關閉在streamReader的關閉之前。這不是偶然的,假如將關閉次序顛倒過來,客戶端將不會獲取到任何文件信息,你可以調試一下看看.這是為什麼呢?原因是假如你在關閉streamWriter 之前關閉streamReader,則你可以以往streamWriter中寫任何東西,但沒有任何資料可以通過通道(通道被關閉了).但希奇的是,我不是已經在之前的streamWriter.println()中輸出了嗎?難道非要等到所有的流關閉之後輸出到客戶端的資訊的東西才能到達?我試著將
streamWriter.close();
streamReader.close();
屏蔽掉,看是否依然能夠實現正常的通信,結果發現不行,程序死機.可能是因為通道沒有閉合導致的.那麼至少可以說明,只有將通道按某種順序正常關閉,才能完成通訊資料的傳輸,否則客戶端收不到資訊.

最後依然是總結一下創建伺服器端程式的步驟
1.用一個你想讓它偵聽傳入客戶機連線的連接埠(例如程式中的3000)來實例化一個ServerSocket(如有問題則拋出Exception)。
2.循環調用ServerSocket的accept()以監聽連接
3.取得客戶端的Socket流以進行讀寫操作
4.包裝流
5.對客戶端的Socket進行讀寫
6.關閉打開的流(切記,永遠不要在關閉Writer 之前關閉Reader),完成通信 

下面是
RemoteFileServer 的程式碼清單

import java.io.*;
import java.net.*; public RemoteFileServer(int aListenPort) {
listenPort = aListenPort;
}
public void acceptConnections() {
try {
ServerSocket server = new ServerSocket(listenPort); .accept();
handleConnection(incomingConnection);
}
} catch (BindException e) {
System.out.println("Unable to bind to port " + listenPort);
} catch (IOException eyst 。 getInputStream();

BufferedReader streamReader = new BufferedReader(new InputStreamReader(inputFromSocket));

FileReader fileReader = new FileReader(new File(streamReader.c.
PrintWriter streamWriter = new PrintWriter(outputToSocket);
String line = null;
while ((line = bufferedFileReader.readLine()) != null) {
streamWriter.printlnline);
streamWriter.close();
streamReader.close();
} catch (Exception e) {
System.out.println("Error handling a client: " + e);
}
}
} static v String[] args) {
RemoteFileServer server = new RemoteFileServer(3000);
server.acceptConnections();
}
}

鳥了,Socket總算是入門了 
}

鳥了。內容,更多相關內容請關注PHP中文網(www.php.cn)! 



陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn