无论用户从界面输入的是文本还是文件,在对端的输入流读取时,依然是一个一个字节读取,所以可以通过约定字节流的传输协议实现文件的传输。
每种消息都由消息头和消息体组成。
消息头包括:
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(); } }
这样就能实现文件从客户端到服务端的传送了!