副标题#e#
一.异常
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;i<args.length;i++){
fileToCheck=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("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.");
}
}
}
#p#副标题#e#
第二个例子是一个存储电话信息的小措施,用户输入姓名和电话号码,措施将其存入phone.numbers文件中,通过FileOutputStream来实现
import java.io.*;
class phones{
static FileOutputStream fos;
public static final int lineLength=81;
public static void main(String args[])throws IOException{
byte[] phone=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('\n');
}
fos.close();
}
private static void readLine(byte line[])throws IOException{
int i=0,b=0;
while((i<(lineLength-1))&&((b=System.in.read())!='\n')){
line[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的浸染,昨天我已经讲了.
此刻,我们将建设一个简朴的通讯措施,以得到对Socket的实质性的认识.该措施包罗两个部门,客户机(RemoteFileClient)和处事器(RemoteFileServer).客户机向处事器发出请求,要求读取处事器上的文件信息.处事器将响应请求,将相应的文件信息传给客户机,将相应的文件信息传给客户机.
首先我们建设RemoteFileClient类:
#p#分页标题#e#
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;
}
public static void main(String[] args) {
}
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.0.0.1", 3000);//为了利便调试,我们把当地处事器看成长途处事器
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工具
OutputStream outToServerStream=client.getOutputStream();
InputStream inFromServerStream=client.getInputStream();
socketReader = new BufferedReader(new InputStreamReader(inFromServerStream));
file&://把/Socket的InputStream包装进BufferedReader 以使我们可以或许读取流的行
socketWriter = new PrintWriter(outToServerStream);
file&://把/Socket的OutputStream包装进PrintWriter 以使我们可以或许发送文件请求随处事器
} catch (UnknownHostException e) {
System.out.println("Error setting up socket connection: unknown host at " + 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工具也是String工具,可是比它更机动,这里是用来存放读取内容的
try {
socketWriter.println(fileNameToGet);
socketWriter.flush();//文件存放地点输出到socketWriter中,然后清空缓冲区,让这个地点送随处事器中去
String line = null;
while ((line = socketReader.readLine()) != null)
fileLines.append(line + "\n");
file&://既/然已经发送随处事器去了,那我们都要期待响应,这里的措施就是期待处事器把我们所需要的文件内容传过来
} catch (IOException e) {
System.out.println("Error reading from file&: " + fileNameToGet);
}
return fileLines.toString();//别忘了把buffer中的内容转成String再返回
}
3.断开
public void tearDownConnection() {
try {
socketWriter.close();
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 的代码清单
#p#分页标题#e#
import java.io.*;
import java.net.*;
public class RemoteFileClient {
protected BufferedReader socketReader;
protected PrintWriter socketWriter;
protected String hostIp;
protected int hostPort;
public RemoteFileClient(String aHostIp, int aHostPort) {
hostIp = aHostIp;
hostPort = aHostPort;
}
public String getFile(String fileNameToGet) {
StringBuffer fileLines = new StringBuffer();
try {
socketWriter.println(fileNameToGet);
socketWriter.flush();
String line = null;
while ((line = socketReader.readLine()) != null)
fileLines.append(line + "\n");
} catch (IOException e) {
System.out.println("Error reading from file&: " + fileNameToGet);
}
return fileLines.toString();
}
public static void main(String[] args) {
RemoteFileClient remoteFileClient = new RemoteFileClient("127.0.0.1", 3000);
remoteFileClient.setUpConnection();
String fileContents = remoteFileClient.getFile("RemoteFile.txt");
remoteFileClient.tearDownConnection();
System.out.println(fileContents);
}
public void setUpConnection() {
try {
Socket client = new Socket(hostIp, hostPort);
OutputStream outToServerStream=client.getOutputStream();
InputStream inFromServerStream=client.getInputStream();
socketReader = new BufferedReader(new InputStreamReader(inFromServerStream));
socketWriter = new PrintWriter(outToServerStream);
} catch (UnknownHostException e) {
System.out.println("Error setting up socket connection: unknown host at " + hostIp + ":" + hostPort);
} catch (IOException e) {
System.out.println("Error setting up socket connection: " + e);
}
}
public void tearDownConnection() {
try {
socketWriter.close();
socketReader.close();
} catch (IOException e) {
System.out.println("Error tearing down socket connection: " + e);
}
}
}
好了,此刻来看处事器端的措施怎么写.
建设RemoteClientServer类:
import java.io.*;
import java.net.*;
public class RemoteFileServer {
protected int listenPort = 3000;
public static void main(String[] args) {
}
public void acceptConnections() {
}
public void handleConnection(Socket incomingConnection) {
}
}
跟客户机中一样,首先导入 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 acceptConnections() {
try {
ServerSocket server = new ServerSocket(listenPort);//同客户机的Socket对应,在处事器端,我们需要ServerSocket工具,参数是兼听的端标语
Socket incomingConnection = null;//建设一个客户端的Socket变量,以吸收从客户端监听到的Socket
while (true) {
incomingConnection = server.accept();//挪用该 ServerSocket 的 accept() 来汇报它开始侦听,
handleConnection(incomingConnection);
}
file&://不/断监听直到来了一个毗连请求,然后交由handleConnection处理惩罚
} catch (BindException e) {
System.out.println("Unable to bind to port " + listenPort);
} catch (IOException e) {
System.out.println("Unable to instantiate a ServerSocket on port: " + listenPort);
}
}
#p#分页标题#e#
无论何时假如建设了一个无法绑定到指定端口(大概是因为此外什么节制了该端口)的 ServerSocket,Java 代码都将抛出一个错误。所以这里我们必需捕获大概的 BindException。同时,与在客户机端上时一样,我们必需捕获 IOException,当我们试图在 ServerSocket 上接管毗连时,它就会被抛出。可以通过用毫秒数挪用 setSoTimeout() 来为 accept() 挪用配置超时,以制止实际长时间的期待。挪用 setSoTimeout() 将使 accept() 颠末指定占用时间后抛出 IOException
最要害的处理惩罚在handleConnection()中,这时已经毗连到了客户端的Socket,要从该Socket中读取客户端的请求而且响应。
public void handleConnection(Socket incomingConnection) {
try {
OutputStream outputToSocket = incomingConnection.getOutputStream();
InputStream inputFromSocket = incomingConnection.getInputStream();
file&://首/先获取同Socket相关联的流outputToSocket和InputStream
file&://其/中outputToSocket是要返回给客户端Socket的流
file&://InputStream/是客户端发来的请求,在这里就是文件路径,即"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(fileReader);
file&://再/次成立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的封锁之前。这不是偶尔的,如果将封锁序次颠倒过来,客户端将不会获取到任何文件信息,你可以调试一下看看.这是为什么呢?原因是假如你在封锁 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 class RemoteFileServer {
int listenPort;
public RemoteFileServer(int aListenPort) {
listenPort = aListenPort;
}
public void acceptConnections() {
try {
ServerSocket server = new ServerSocket(listenPort);
Socket incomingConnection = null;
while (true) {
incomingConnection = server.accept();
handleConnection(incomingConnection);
}
} catch (BindException e) {
System.out.println("Unable to bind to port " + listenPort);
} catch (IOException e) {
System.out.println("Unable to instantiate a ServerSocket on port: " + listenPort);
}
}
public void handleConnection(Socket incomingConnection) {
try {
OutputStream outputToSocket = incomingConnection.getOutputStream();
InputStream inputFromSocket = incomingConnection.getInputStream();
BufferedReader streamReader = new BufferedReader(new InputStreamReader(inputFromSocket));
FileReader fileReader = new FileReader(new File(streamReader.readLine()));
BufferedReader bufferedFileReader = new BufferedReader(fileReader);
PrintWriter streamWriter = new PrintWriter(outputToSocket);
String line = null;
while ((line = bufferedFileReader.readLine()) != null) {
streamWriter.println(line);
}
fileReader.close();
streamWriter.close();
streamReader.close();
} catch (Exception e) {
System.out.println("Error handling a client: " + e);
}
}
public static void main(String[] args) {
RemoteFileServer server = new RemoteFileServer(3000);
server.acceptConnections();
}
}