无论用户从界面输入的是文本还是文件,在对端的输入流读取时,依然是一个一个字节读取,所以可以通过约定字节流的传输协议实现文件的传输。
每种消息都由消息头和消息体组成。
消息头包括:
1、 消息总长totalLen:指这条消息一共有多少字节,用一个Int(四个字节)来表示
2、 消息类型:用一个byte来定义,2代表传输文件消息。
对于文件传输来说,消息体包括:
3、 文件名的长度len:文件名的字节数,用一个byte来表示
4、 文件名:用一个byte数组表示。
5、 文件中的数据:用一个byte数组来表示,长度为totalLen-4-1-1-len。
服务器端按照以上协议模式依次从输入流中读取消息头和消息体,再输出还原为原本的文件:
private void processChat(java.net.Socket client){
try{
java.io.OutputStream ous = client.getOutputStream();
java.io.InputStream ins = client.getInputStream();
java.io.DataInputStream dins = new java.io.DataInputStream(ins);
while(true){
int totalLen = dins.readInt();//总长度
byte type = dins.readByte();//类型
if(type==2){//文 件类型
byte len = dins.readByte();//文件名长度
byte[] fn = new byte[len];
dins.read(fn);//读取文件名
byte[] data = new byte[totalLen -1-4-1-fn.length];//文件数据
dins.readFully(data);
dins.close();//文件读取完要关闭
java.io.FileOutputStream fous = new java.io.FileOutputStream("D:\\1.txt");
fous.write(data);
fous.flush();
fous.close();
}
}
}catch(Exception ef){
ef.printStackTrace();
}
}
客户端:首先根据文件构造一个输出流对象,按照协议依次写出消息头和消息体的数据,实现如下:
/**
* 发送一个文件数据包
* @param fileName:文件的绝对路径
*/
private void sendFileMsg(String fileName){
try{
//根据文件的绝对路径创建文件对象
File file = new File(fileName);
//根据文件对象,构造一个输入流
FileInputStream fins = new FileInputStream(file);
int fileDataLen = fins.available(); //数据的总长度
byte type = 2; //文件的类型为2,即传文件
//得到文件名
String f_name=file.getName();
byte f_len=(byte) file.getName().length();
int totalLen = 4+1+1+f_len+fileDataLen;//数据的总长度
byte[] data=new byte[f_len];
data=f_name.getBytes();
dous.writeInt(totalLen); //1.写入数据的总长度
System.out.println("数据总长度为:"+totalLen);
dous.writeByte(type);//2.写入文件类型
System.out.println("数据类型为:"+type);
dous.writeByte(f_len); //3.写入文件名的长度
System.out.println("文件名的长度为:"+f_len);
dous.write(data); //4.写入文件名的数据
System.out.println("文件名为:"+f_name);
byte[] fileData=new byte[fileDataLen];
fins.read(fileData);//读入文件数据写入fileData数组中去
dous.write(fileData);//写出到服务器的流中
dous.flush(); //刷新流
}catch(Exception e){
e.printStackTrace();
}
}
这样就能实现文件从客户端到服务端的传送了!