? ? ? ? 作为一个初学者,最近在开始学习Java语言,该说不说,学习一门编程语言确实是有点枯燥,哈哈哈哈。每天就是看视频,敲代码,反反复复,唉。所以为了增加点乐趣,写个小程序,总结下这两天学到的东西。
? ? ? ? 整个程序思路很简单,就是:客户端获取到服务端可下载的文件,选择其中一个进行下载。
? ? ? ? 实现过程:
? ? ? ? 服务端
? ? ? ? ? ? ? ? 1、获取指定文件夹下的所有文件对象(使用listFile),存入集合。
/*递归获取服务端指定文件夹下所有可供下载的文件
* 存到集合中,将此集合返回*/
public static ArrayList<File> getFiles(File e) {
File[] list = e.listFiles();
for (File x : list) {
if (x.isDirectory()) {
getFiles(x);
} else if (!x.isDirectory()) {
fileList.add(x);
}
}
return fileList;
}
? ? ? ? ? ? ? ? 2、将集合序列化,存入本地,生成txt文件。
ObjectOutputStream write = new ObjectOutputStream(new FileOutputStream("SocketPrj\\src\\FileDownLoad\\服务端配置文件.txt"));
write.writeObject(fileList); //序列化集合对象,将集合对象发送到客户端然后反序列化,然后展示可以下载的文件
? ? ? ? ? ? ? ? 3、将序列化后的文件发送至客户端,这样就可以每次运行程序,客户端就可以获取到最新的服务端可供下载的所有的文件。当然,这只是其中的一种实现方式,主要是想复习下序列化和反序列化。
conSocket = serverSocket.accept();
System.out.println("连接成功,开始发送文件列表...");
OutputStream output = conSocket.getOutputStream();
FileInputStream getSetFile = new FileInputStream("SocketPrj\\src\\FileDownLoad\\服务端配置文件.txt"); //准备读取集合序列化文件
byte[] bt = new byte[1024];
int len = 0;
while ((len = getSetFile.read(bt)) != -1) {
output.write(bt, 0, len);
}
conSocket.shutdownOutput();
write.close();
System.out.println("配置文件发送完成");
? ? ? ? ? ? ? ? 4、接收客户端请求下载的文件,然后向客户端发送指定的文件。
fileSocket = serverSocket.accept(); //新开的负责文件发送的socket
System.out.println("客户端选择下载的文件是:" + downLoadFileName + ",开始发送...");
for (File x : fileList) {
if (downLoadFileName.equals(x.getName())) {
FileInputStream readFile = new FileInputStream(x);
BufferedInputStream bfReader = new BufferedInputStream(readFile); //读取将发送的本地文件
OutputStream out = fileSocket.getOutputStream();
byte[] bt = new byte[1024]; //设置每次发送数据的大小
int len = 0;
while ((len = bfReader.read(bt)) != -1) {
out.write(bt, 0, len);
}
fileSocket.shutdownOutput(); //通知客户端文件已发送完毕,关闭读取
break;
}
}
? ? ? ? 客户端
? ? ? ? ? ? ? ? 1、反序列化服务端发来的txt文件,获取到可下载的文件对象并且展示到控制台。
//本地配置文件,存储的是可供下载的文件对象
FileOutputStream writeSetFile = new FileOutputStream("SocketPrj\\src\\FileDownLoad\\客户端配置文件.txt");
//接收服务端发来的配置文件
BufferedOutputStream bfWriterSetFile = new BufferedOutputStream(writeSetFile);
conSocket = new Socket(InetAddress.getLocalHost(), 8848);
System.out.println("连接成功,正在接收配置文件(文件集合)");
InputStream in = conSocket.getInputStream();
byte[] bt = new byte[1024];
int len = 0;
while ((len = in.read(bt)) != -1) {
bfWriterSetFile.write(bt, 0, len);
bfWriterSetFile.flush();
}
bfWriterSetFile.close();
System.out.println("获取成功!");
//返序列化文件,获取存储的文件对象
ObjectInputStream getSetFiles = new ObjectInputStream(new FileInputStream("SocketPrj\\src\\FileDownLoad\\客户端配置文件.txt"));
Object obj = getSetFiles.readObject();
ArrayList<File> list = (ArrayList<File>) obj;
getSetFiles.close();
ArrayList<String> tempList = new ArrayList<>();
System.out.println("服务器可供下载文件有:");
for (File x : list) {
tempList.add(x.getName());
System.out.println(x.getName());
}
? ? ? ? ? ? ? ? 2、根据展示内容选择要下载的文件,发送下载请求。
/*接收用户输入的想下载的文件,输入不存在的文件名
* 就会一直处于输入状态
* 输入正确跳出循环
* 正确后向服务端发送下载请求*/
while (true) {
System.out.print("输入你想下载的文件名:");
str = new Scanner(System.in).nextLine();
if (tempList.contains(str)) {
System.out.println("输入正确,等待下载...");
break;
} else {
System.out.println("你输入的文件不存在!请重新输入:");
}
}
/*向服务器发送下载请求*/
OutputStream out = conSocket.getOutputStream();
out.write(str.getBytes());
conSocket.shutdownOutput();
System.out.println("请求发送成功,等待下载...");
conSocket.close();
? ? ? ? ? ? ? ? 3、接收服务端发来的文件,存入本地文件夹。
//因为第一个负责通信的socket使用了shutdownOutput,导致无法使用其继续发送数据
//所以新开一个socket专门负责发文件
fileSocket = new Socket(InetAddress.getLocalHost(), 8848);
System.out.println("开始下载文件...");
FileOutputStream writer = new FileOutputStream("SocketPrj\\ClientFiles\\" + str);
InputStream in = fileSocket.getInputStream();
byte[] bt = new byte[1024];
int len;
while ((len = in.read(bt)) != -1) {
writer.write(bt, 0, len);
}
System.out.println("下载成功!");
服务端完整代码:
package FileDownLoad;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
/*文件下载之服务端
* 作者:小刘同学
* 时间:2021年10月21日 23点28分
* 目的:复习巩固下socket编程
* */
public class ServerAllFiles extends Thread {
static ArrayList<File> fileList = new ArrayList<>(); //存储可供下载文件对象的集合
static ServerSocket serverSocket; //服务端Socket,建立监听对象
static String downLoadFileName = null; //接收客户端发过来的文件名
static Socket conSocket = null; //负责和客户端通信的socket
static Socket fileSocket = null; //接收文件的socket
public static void main(String[] args) throws IOException, InterruptedException {
ServerAllFiles th = new ServerAllFiles();
th.start();
}
@Override
public void run() {
File allFiles = new File("SocketPrj\\ServerAllFiles");
getFiles(allFiles);
try {
sendSetFile();
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/*递归获取服务端指定文件夹下所有可供下载的文件
* 存到集合中,将此集合返回*/
public static ArrayList<File> getFiles(File e) {
File[] list = e.listFiles();
for (File x : list) {
if (x.isDirectory()) {
getFiles(x);
} else if (!x.isDirectory()) {
fileList.add(x);
}
}
return fileList;
}
/*发送配置文件(里面装的是可供下载文件的名字)*/
public static void sendSetFile() throws IOException, InterruptedException {
ObjectOutputStream write = new ObjectOutputStream(new FileOutputStream("SocketPrj\\src\\FileDownLoad\\服务端配置文件.txt"));
write.writeObject(fileList); //序列化集合对象,将集合对象发送到客户端然后反序列化,然后展示可以下载的文件
System.out.println("列表更新完成");
serverSocket = new ServerSocket(8848);
System.out.println("正在等待客户端连接...");
conSocket = serverSocket.accept();
System.out.println("连接成功,开始发送文件列表...");
OutputStream output = conSocket.getOutputStream();
FileInputStream getSetFile = new FileInputStream("SocketPrj\\src\\FileDownLoad\\服务端配置文件.txt"); //准备读取集合序列化文件
byte[] bt = new byte[1024];
int len = 0;
while ((len = getSetFile.read(bt)) != -1) {
output.write(bt, 0, len);
}
conSocket.shutdownOutput();
write.close();
System.out.println("配置文件发送完成");
System.out.println("等待接收下载请求...");
InputStream in = conSocket.getInputStream();
byte[] btRecive = new byte[1024];
int lenRecive = 0;
downLoadFileName = null; //接收客户端发过来的下载文件名
while ((lenRecive = in.read(btRecive)) != -1) {
downLoadFileName = new String(btRecive, 0, lenRecive);
}
conSocket.close();
recivePost();
}
/*接收客户端下载请求
* 发送文件*/
public static void recivePost() throws IOException {
fileSocket = serverSocket.accept(); //新开的负责文件发送的socket
System.out.println("客户端选择下载的文件是:" + downLoadFileName + ",开始发送...");
for (File x : fileList) {
if (downLoadFileName.equals(x.getName())) {
FileInputStream readFile = new FileInputStream(x);
BufferedInputStream bfReader = new BufferedInputStream(readFile); //读取将发送的本地文件
OutputStream out = fileSocket.getOutputStream();
byte[] bt = new byte[1024]; //设置每次发送数据的大小
int len = 0;
while ((len = bfReader.read(bt)) != -1) {
out.write(bt, 0, len);
}
fileSocket.shutdownOutput(); //通知客户端文件已发送完毕,关闭读取
break;
}
}
System.out.println("发送完成,客户端已接收到文件!");
}
}
客户端完整代码
package FileDownLoad;
import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Scanner;
public class ClientDownCls extends Thread {
/*文件下载之客户端
* 作者:小刘同学
* 时间2021年10月21日 23点28分
* 目的:复习巩固下socket编程
* */
static Socket conSocket;
static Socket fileSocket;
static String str = null;
public static void main(String[] args) throws IOException, ClassNotFoundException {
ClientDownCls client = new ClientDownCls();
client.start();
}
@Override
public void run() {
try {
getSetFile(); //其中包含展示可下载的文件列表,以及下载文件
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
/*接收服务端传过来的配置文件(文件集合)*/
public static void getSetFile() throws IOException, ClassNotFoundException {
//本地配置文件,存储的是可供下载的文件对象
FileOutputStream writeSetFile = new FileOutputStream("SocketPrj\\src\\FileDownLoad\\客户端配置文件.txt");
//接收服务端发来的配置文件
BufferedOutputStream bfWriterSetFile = new BufferedOutputStream(writeSetFile);
conSocket = new Socket(InetAddress.getLocalHost(), 8848);
System.out.println("连接成功,正在接收配置文件(文件集合)");
InputStream in = conSocket.getInputStream();
byte[] bt = new byte[1024];
int len = 0;
while ((len = in.read(bt)) != -1) {
bfWriterSetFile.write(bt, 0, len);
bfWriterSetFile.flush();
}
bfWriterSetFile.close();
System.out.println("获取成功!");
getList();
}
/*读取配置文件,获取集合对象
* 选择下载文件,将用户选择的下载的文件的请求发回服务器
* */
public static void getList() throws IOException, ClassNotFoundException {
//返序列化文件,获取存储的文件对象
ObjectInputStream getSetFiles = new ObjectInputStream(new FileInputStream("SocketPrj\\src\\FileDownLoad\\客户端配置文件.txt"));
Object obj = getSetFiles.readObject();
ArrayList<File> list = (ArrayList<File>) obj;
getSetFiles.close();
ArrayList<String> tempList = new ArrayList<>();
System.out.println("服务器可供下载文件有:");
for (File x : list) {
tempList.add(x.getName());
System.out.println(x.getName());
}
System.out.println("=================================="); //华丽的的分割线
/*接收用户输入的想下载的文件,输入不存在的文件名
* 就会一直处于输入状态
* 输入正确跳出循环
* 正确后向服务端发送下载请求*/
while (true) {
System.out.print("输入你想下载的文件名:");
str = new Scanner(System.in).nextLine();
if (tempList.contains(str)) {
System.out.println("输入正确,等待下载...");
break;
} else {
System.out.println("你输入的文件不存在!请重新输入:");
}
}
/*向服务器发送下载请求*/
OutputStream out = conSocket.getOutputStream();
out.write(str.getBytes());
conSocket.shutdownOutput();
System.out.println("请求发送成功,等待下载...");
conSocket.close();
downFile();
}
/*接收服务端发来的文件*/
public static void downFile() throws IOException {
//因为第一个负责通信的socket使用了shutdownOutput,导致无法使用其继续发送数据
//所以新开一个socket专门负责发文件
fileSocket = new Socket(InetAddress.getLocalHost(), 8848);
System.out.println("开始下载文件...");
FileOutputStream writer = new FileOutputStream("SocketPrj\\ClientFiles\\" + str);
InputStream in = fileSocket.getInputStream();
byte[] bt = new byte[1024];
int len;
while ((len = in.read(bt)) != -1) {
writer.write(bt, 0, len);
}
System.out.println("下载成功!");
}
}
运行截图:
?
?
总结一句话就是:服务端,读出来-发出去 | 客户端,接收到,写进去
????????我觉得其中有一个值得需注意的问题,就是需要对socket对象使用shutdownOutput方法,不使用这个方法,又会出现程序阻塞,有小伙伴知道阻塞原因吗?(嘿嘿嘿)。不过使用后就无法继续使用该socket对象发送数据,一时想不到解决办法,想的就是只有重新创建一个socket负责发送数据。但是感觉这样不妥,于是百度了下,好像这也算是一种解决办法,其他方法倒是没找到。不知道还有没有其他更好的方法。
? ? ? ? 最后,不用知道为啥心血来潮,想写这篇博客,也算是第一个文章,哈哈哈哈,可能主要是向纪念下吧。当然,程序很简单,也有很多问题,还请大家不吝赐教。完整代码贴在上面了,有需要的小伙伴可以参考下哦,大家一起加油,冲冲冲
|