代码主要注意使用文件选择器的时候,读取文件语句while((len = in.read(bytes)) > 0)
,会一直卡在这个循环中,所以只能传送一次文件
因此我们要在读取文件的时候,加入文件截至符:
1 发送文件时,将文件截至符以byte
的数据类型写入文件
// 传送文件截至符
out.write("##end".getBytes() , 0, 5); // 获取字节数组
2 接受文件时,我们要判断文件是否读到截至符
// 判断文件是否结束
String end = new String(bytes, 0, len);
if(end.substring(end.length() - 5).equals("##end"))
{
fileOut.write(end.substring(0, end.length()-5).getBytes() ,0, end.length()-5);
fileOut.flush();
break;
}
服务端
package Platform;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
class ServerGUI extends JFrame
{
JTextArea showArea; // 显示文本框
JTextField sendfield; // 端口文本框
serthread st; // 线程
Startbtnpolice startbtnpolicebp; // 开始按钮的监听器
Sentbtnpolice sentbtnpolice; // 发送按钮的监听器
JTextField portfield; // 端口的文本框
// 开始按钮监听器
private class Startbtnpolice implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
if(portfield.getText().equals("1999"))
showArea.append("Server starting… "+"\n" );
else
showArea.append("非法端口" + "\n");
}
}
// 发送按钮监听器
private class Sentbtnpolice extends KeyAdapter implements ActionListener //
{
public void actionPerformed(ActionEvent e)
{
st.sentmssage(sendfield.getText());
showArea.append("发送文件:" + sendfield.getText() + "\n");
sendfield.setText("");
}
public void keyTyped(KeyEvent ke)
{
if(ke.getKeyCode() == KeyEvent.VK_ENTER)
{
st.sentmssage(sendfield.getText());
showArea.append("发送文件:" + sendfield.getText() + "\n");
sendfield.setText("");
}
}
}
public void setthread(serthread st)
{
this.st = st;
}
public ServerGUI()
{
super("服务器");
Container contain = getContentPane();
// 实例化监听器
startbtnpolicebp = new Startbtnpolice();
sentbtnpolice = new Sentbtnpolice();
// 显示文本框设置
showArea = new JTextArea(5,20);
JScrollPane js = new JScrollPane(showArea);
contain.add(js);
// 顶端布局设置
JPanel upPanel = new JPanel();
upPanel.setLayout(new FlowLayout());
JButton startbtn = new JButton("Start");
startbtn.addActionListener(startbtnpolicebp);
JLabel portlabel=new JLabel("Port:",SwingConstants.LEFT);
portfield=new JTextField(30);
portfield.setText("1999");
upPanel.add(portlabel);
upPanel.add(portfield);
upPanel.add(startbtn);
contain.add(upPanel, BorderLayout.NORTH);
// 底端布局设置
JPanel downpanel = new JPanel();
downpanel.setLayout(new FlowLayout());
sendfield = new JTextField(30); // 发送文件文本框
JButton sendbtn = new JButton("Send");
sendbtn.addActionListener(sentbtnpolice);
//
sendbtn.addKeyListener(sentbtnpolice);
downpanel.add(new JLabel("File Path:"));
downpanel.add(sendfield);
downpanel.add(sendbtn);
contain.add(downpanel, BorderLayout.SOUTH);
setSize(600, 400);
setVisible(true);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
}
class serthread extends Thread
{
Socket socketonserver; // 自身的套接字
ServerSocket socketforclient; // 返回客户端的套接字
DataInputStream in; // 输入数据流
DataOutputStream out; // 输出数据流
ServerGUI gui; // 利用gui发送消息,使其显示在文本框中
public serthread(ServerGUI Gui)
{
try
{
gui = Gui;
gui.setthread(this); // 获得线程,最后利用线程在监听器中发送消息,其实在实例化主线程的st,进而完成监听器的操作
socketforclient = new ServerSocket(1999); // 返回客户端是1999的套接字
socketonserver = socketforclient.accept(); // 建立连接
// 接受发出数据流
in = new DataInputStream(socketonserver.getInputStream()); // 读取接受文件名
out = new DataOutputStream(socketonserver.getOutputStream()); // 读取发送文件名
}
catch(IOException e)
{
System.out.println(e);
}
}
public void run()
{
String filename; // 接受到的文件名(包含地址)
// 不断获取信息
while(true)
{
try
{
System.out.println("有文件了");
filename = in.readUTF(); // 获取接收到的文件名
gui.showArea.append("接收文件:" + filename + "\n");
System.out.println(filename); // 先输出文件名
// 获取文件名(不带路径)
String newpath = null; // 不带路径的文件名
for(int i = 0;i < filename.length();i++)
{
char c = filename.charAt(i);
if(c == '\\')
newpath = filename.substring(i + 1);
}
// 在本地创建文件
File file = new File("C:\\Users\\dell\\Desktop\\Experiment2_Chat 传文件\\文件下载地址\\" + newpath); // 写本地文件(固定地址)
if(!file.exists())
file.createNewFile();
// 在本地写文件
FileOutputStream fileOut = new FileOutputStream(file);
byte bytes[] = new byte[1024]; // 读取的内容数据
int len;
while((len = in.read(bytes)) > 0)
{
// 判断文件是否结束
String end = new String(bytes, 0, len);
if(end.substring(end.length() - 5).equals("##end"))
{
fileOut.write(end.substring(0, end.length()-5).getBytes(),0,end.length()-5);
fileOut.flush();
break;
}
fileOut.write(bytes, 0, len); // 读取一部分内容
fileOut.flush(); // 刷新缓存区
}
// 关闭流
fileOut.close();
}
catch(Exception e)
{
System.out.println(e.getMessage());
break;
}
}
}
// 发送消息
public void sentmssage(String filename)
{
try
{
// 传送文件名
out.writeUTF(filename);
// 打开文件
File file = new File("C:\\Users\\dell\\Desktop\\2019215053 杨雨润\\Experiment2_Chat 作业5\\文件来源\\" + filename);
FileInputStream filein = new FileInputStream(file); // 传送文件流
// 开始传送文件
byte bytes[] = new byte[1024];
int l;
while((l = filein.read(bytes)) > 0)
{
out.write(bytes, 0, l);
out.flush();
}
// 传送文件截至符
out.write("##end".getBytes() , 0, 5); // 获取字节数组
}
catch(Exception e)
{
System.out.println(e);
}
}
}
public class Serve
{
public static void main(String args[])
{
ServerGUI sGUI = new ServerGUI();
serthread st = new serthread(sGUI);
st.start();
}
}
客户端
package Platform;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.*;
import java.net.Socket;
class ClientGUI extends JFrame
{
JTextArea showArea; // 输出文本框
JTextField sendfield; // 发送框
clithread ct; // 自定义客户端线程
JTextField ipfield; // IP地址输入框
JTextField portfield; // Port发送框
JButton connectbtn; // 连接按钮
Connectbtnpolice connectbtnpolice; // 连接按钮监听器
Sendbtnpolice sendbtnpolice; // 发送按钮监听器
// 连接按钮监听器
private class Connectbtnpolice implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
System.out.println(portfield.getText());
if(portfield.getText().equals( "1999"))
{
showArea.append("Connect to server…" + "\n");
// 连接成功以后开始创造线程
ct = new clithread(ipfield.getText(), 1999, ClientGUI.this);
ClientGUI.this.setthread(ct);
showArea.append("Client connected…" + "\n");
}
else
{
showArea.append("非法端口" + "\n");
}
}
}
// 发送按钮监听器
private class Sendbtnpolice implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
ct.sentmessage(sendfield.getText()); // 带路径的文件名
showArea.append("发送文件: " + sendfield.getText() + "\n");
sendfield.setText("");
}
}
//构造函数
public void setthread(clithread ct)
{
this.ct = ct;
}
public void showFileOpenDialog(Component parent, JTextField msgTextArea)
{
// 创建一个默认的文件选取器
JFileChooser fileChooser = new JFileChooser();
// 设置默认显示的文件夹为当前文件夹
fileChooser.setCurrentDirectory(new File("."));
// 设置文件选择的模式(只选文件、只选文件夹、文件和文件均可选)
fileChooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
// 打开文件选择框(线程将被阻塞, 直到选择框被关闭)
int result = fileChooser.showOpenDialog(parent); // 正真打开选择对话框 parent就是父窗口
if (result == JFileChooser.APPROVE_OPTION) {
// 如果点击了"确定", 则获取选择的文件路径
/*返回值:
* JFileChooser.CANCEL_OPTION: 点击了取消或关闭
* JFileChooser.APPROVE_OPTION: 点击了确认或保存
* JFileChooser.ERROR_OPTION: 出现错误*/
// 获得被选择文件
File file = fileChooser.getSelectedFile();
msgTextArea.setText(file.getAbsolutePath());
}
}
public ClientGUI()
{
super("客户端");
// 布局
Container contain = getContentPane(); // 获得容器面板
contain.setLayout(new BorderLayout());
// 实例化监听器
connectbtnpolice = new Connectbtnpolice();
sendbtnpolice = new Sendbtnpolice();
// 对话文本框
showArea = new JTextArea(10,30);
contain.add(new JScrollPane(showArea), BorderLayout.CENTER);
// 顶端布局
JPanel upPanel = new JPanel();
upPanel.setLayout(new FlowLayout());
upPanel.add(new JLabel("Server IP:"));
ipfield = new JTextField(15);
ipfield.setText("127.0.0.1");
upPanel.add(ipfield);
upPanel.add(new JLabel("Serve Port:"));
portfield =new JTextField(8);
upPanel.add(portfield);
connectbtn = new JButton("Connect");
connectbtn.addActionListener(connectbtnpolice);
upPanel.add(connectbtn);
contain.add(upPanel, BorderLayout.NORTH);
// 底端布局
JPanel downpanel = new JPanel();
downpanel.setLayout(new FlowLayout()); // 面板
sendfield = new JTextField(30);//发送文本框
JButton sendBtn = new JButton("Send"); // 发送按钮
sendBtn.addActionListener(sendbtnpolice);
downpanel.add(new JLabel("File Path:"));
downpanel.add(sendfield);
// 创建 打开文件按钮
JButton openBtn = new JButton("打开文件");
openBtn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
showFileOpenDialog(ClientGUI.this, sendfield); // 打开文件对话框,创建自己的类,第一个参数是父窗口,第二个是显示文本框
}
});
downpanel.add(openBtn);
downpanel.add(sendBtn);
contain.add(downpanel, BorderLayout.SOUTH);
setSize(600, 400);
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
class clithread extends Thread
{
Socket ct; // 自己的套接字
ClientGUI cGUI; // 调用窗口显示文本
DataInputStream in;
DataOutputStream out;
// 构造函数
public clithread(String IP, int Port, ClientGUI cgui)
{
try
{
cGUI = cgui;
ct = new Socket(IP, Port);
in = new DataInputStream(ct.getInputStream());
out = new DataOutputStream(ct.getOutputStream());
}
catch (Exception e)
{
System.out.println(e);
}
start();
}
public void run()
{
String filename;
// 获取信息
while(true)
{
try
{
filename = in.readUTF(); // 获取接收到的文件名(带路径)
cGUI.showArea.append("接收文件:" + filename + "\n");
System.out.println(filename); // 先输出文件名
// // 获取文件名(不带路径)
// String newpath = null; // 不带路径的文件名
// for(int i = 0;i < filename.length();i++)
// {
// char c = filename.charAt(i);
//
// if(c == '\\')
// newpath = filename.substring(i + 1);
// }
// 在本地创建文件
File file = new File("C:\\Users\\dell\\Desktop\\2019215053 杨雨润\\Experiment2_Chat 作业5\\文件下载地址\\" + filename); // 写本地文件(固定地址)
if(!file.exists())
file.createNewFile();
System.out.println("文件建好了");
// 在本地写文件
FileOutputStream fileOut = new FileOutputStream(file);
byte bytes[] = new byte[1024]; // 读取的内容数据
int len;
while((len = in.read(bytes)) != -1)
{
// 判断文件是否结束
String end = new String(bytes, 0, len); // 解码,将字节转换为String
if(end.substring(end.length() - 5).equals("##end"))
{
fileOut.write(end.substring(0, end.length()-5).getBytes(),0,end.length()-5);
fileOut.flush();
break;
}
fileOut.write(bytes, 0, len); // 读取一部分内容
fileOut.flush(); // 刷新缓存区
}
// 关闭流
fileOut.close();
}
catch(Exception e)
{
System.out.println(e);
break;
}
}
}
// 发送消息
public void sentmessage(String filename)
{
try
{
// 传送文件名
out.writeUTF(filename); // 文件名带路径
// 打开文件
File file = new File(filename);
FileInputStream filein = new FileInputStream(file); // 传送文件流
// 开始传送文件
byte bytes[] = new byte[1024];
int l;
while((l = filein.read(bytes)) > 0) // 将数据读入bytes数组中,返回字节数
{
out.write(bytes, 0, l); // 将bytes数组中的数据写出,从off开始,总共长度是l
out.flush();
}
// 传送文件截至符
out.write("##end".getBytes() , 0, 5); // 获取字节数组
System.out.println("文件发完了");
}
catch (Exception e)
{
System.out.println(e);
}
}
}
public class Client
{
public static void main(String[] args)
{
ClientGUI cGUI = new ClientGUI();
}
}