day04-2发送文件
多用户即时通讯系统04
4.编码实现03
4.6功能实现-发送文件功能实现
4.6.1思路分析
客户端(发送者):
- 先把文件a.jpg读取到客户端的字节数组
- 把文件对应的字节数组封装到message对象[包含文件内容,发送者,接收者]
- 将message对象发送到服务端
服务端:
- 接收到message对象
- 拆解message对象的getteruid,获取接收者用户的通信线程,得到socket
- 把message转发给指定用户
客户端(接收者):
- 在接收到包含有文件的message消息后,读取对应的文件字节数组,将该数组刷出到磁盘
4.6.2代码实现
1. 客户端:
1.修改MessageType接口
在该接口中拓展消息类型
String MESSAGE_FILE_MES = "8";//表示发送文件消息
2.修改Message类
扩展 和文件相关的成员和方法
//进行扩展 和文件相关的成员 private byte[] fileBytes; private int fileLen = 0; private String dest ;//将文件传输到哪里 private String src;//源文件路径 public byte[] getFileBytes() { return fileBytes; } public void setFileBytes(byte[] fileBytes) { this.fileBytes = fileBytes; } public int getFileLen() { return fileLen; } public void setFileLen(int fileLen) { this.fileLen = fileLen; } public String getDest() { return dest; } public void setDest(String dest) { this.dest = dest; } public String getSrc() { return src; } public void setSrc(String src) { this.src = src; }
3.创建FileClientService
该类完成文件传输服务
package qqclient.service; import qqcommon.Message; import qqcommon.MessageType; import java.io.*; /** * @author 李 * @version 1.0 * 该类完成 文件传输服务 */ public class FileClientService { /** * @param src 源文件 * @param dest 把该文件传输到对方的哪个目录 * @param senderId 发送用户的id * @param getterId 接收用户的id */ public void sendFileToOne(String src, String dest, String senderId, String getterId) { //读取src文件--封装-->message对象 Message message = new Message(); message.setMesType(MessageType.MESSAGE_FILE_MES);//设置为文件类型 message.setSender(senderId); message.setGetter(getterId); message.setSrc(src); message.setDest(dest); //需要将文件读取到程序中 FileInputStream fileInputStream = null; byte[] fileBytes = new byte[(int) new File(src).length()];//创建一个和文件大小对应的字节数组 try { fileInputStream = new FileInputStream(src); fileInputStream.read(fileBytes);//将src的文件读入到程序的字节数组 //将文件对应的字节数组设置成message对象 message.setFileBytes(fileBytes); } catch (Exception e) { e.printStackTrace(); } finally { if (fileInputStream != null) { try { //关闭流 fileInputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } System.out.println("\n" + senderId + " 给 " + getterId + " 发送文件:" + src + " 到对方的电脑目录: " + dest); //发送 try { //从管理线程的集合中,拿到发送者id的线程, // 在该线程对应的属性socket中得到输出流,将输出流转为对象输出流 ObjectOutputStream oos = new ObjectOutputStream(ManageClientConnectServerThread.getClientConnectServerThread(senderId).getSocket().getOutputStream()); oos.writeObject(message); } catch (IOException e) { e.printStackTrace(); } } }
4.修改ClientConnectServerThread类
在在该类中增加接收message消息的类型,并进行相应的操作
else if (message.getMesType().equals(MessageType.MESSAGE_FILE_MES)) { //接收到的是文件类型的消息 //把服务器转发的message对象 System.out.println("\n" + message.getSender() + " 给 " + message.getGetter() + " 发送文件: " + message.getSrc() + " 到我的电脑的目录:" + message.getDest()); //取出message文件的字节数组,通过文件输出流写出到磁盘 FileOutputStream fileOutputStream = new FileOutputStream(message.getDest()); fileOutputStream.write(message.getFileBytes()); fileOutputStream.close(); System.out.println("\n保存文件成功~"); }

5.修改QQView
1.在该类中创建FileClientService对象
private FileClientService fileClientService = new FileClientService();//该对象用于文件传输
在该类中通过键盘,将用户输入传送到sendFileToOne方法中

case "4": System.out.println("请输入你希望发送文件的用户(在线):"); getterId = Utility.readString(50); System.out.println("请输入要发送文件的路径:(形式如:d:\\xx.jpg)"); String src = Utility.readString(100); System.out.println("请输入把文件发送到对方电脑下的路径:(形式如:d:\\yy.jpg)"); String dest = Utility.readString(100); fileClientService.sendFileToOne(src,dest,userId,getterId); break;
2.服务端
1.修改MessageType接口
在该接口中拓展消息类型
String MESSAGE_FILE_MES = "8";//表示发送文件消息
2.修改Message类
扩展 和文件相关的成员和方法
//进行扩展 和文件相关的成员 private byte[] fileBytes; private int fileLen = 0; private String dest ;//将文件传输到哪里 private String src;//源文件路径 public byte[] getFileBytes() { return fileBytes; } public void setFileBytes(byte[] fileBytes) { this.fileBytes = fileBytes; } public int getFileLen() { return fileLen; } public void setFileLen(int fileLen) { this.fileLen = fileLen; } public String getDest() { return dest; } public void setDest(String dest) { this.dest = dest; } public String getSrc() { return src; } public void setSrc(String src) { this.src = src; }
3.修改ServerConnectClientThread类
在该类的run方法中增加服务端接收文件并转发的业务
else if (message.getMesType().equals(MessageType.MESSAGE_FILE_MES)) { //业务五:客户请求给某用户发送文件 //根据接收的message对象的getter id 获取到对应的线程,将message对象进行转发 //拿到线程 ServerConnectClientThread serverConnectClientThread = ManageClientThreads.getServerConnectClientThread(message.getGetter()); //获取socket,将socket输出流转为对象流 ObjectOutputStream oos = new ObjectOutputStream(serverConnectClientThread.getSocket().getOutputStream()); //转发 oos.writeObject(message); }
运行:
1.运行服务端

2.运行客户端,登录两个用户(100,200)

3.用户100 尝试给用户200 发送文件
用户100:

用户200:

用户200的磁盘下成功接收到文件:

4.服务端

功能实现完毕
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!