[Java] 文件上传下载项目(详细注释)

时间:2023-03-08 22:47:11

先上代码,最上方注释是文件名称(运行时要用到)

FTServer.java

 /*
FTServer.java
*/ import java.util.*;
import java.io.*; public class FTServer { public static File share = null; public static void main(String[] args) throws Exception { int port = ; //加载配置文件
Properties p = new Properties();
p.load(FTServer.class.getClassLoader().getResourceAsStream("server.properties")); //获取服务器的存储路径
share = new File(p.getProperty("share")); if(!share.isDirectory()) {
System.out.println("share directory not exists or isn't a directory");
System.exit(-);
} //读取服务器与客户机交互的端口号
port = Integer.parseInt(p.getProperty("port")); FTProtocol protocol = new FTProtocol();
AdvancedSupport as = new AdvancedSupport(protocol);
NwServer nw = new NwServer(as,port); } }

FTClient.java

 /*
FTClient.java
*/ import java.net.*;
import java.io.*;
import java.util.*; public class FTClient { Socket s = null;
DataInputStream dis = null;
DataOutputStream dos = null; String[] args = null; public void start(String server, int port) throws Exception {
s = establish(server, port);//new一个socket
dis = new DataInputStream(s.getInputStream());
dos = new DataOutputStream(s.getOutputStream()); if (args[].equals("get")) {//获取文件
dos.writeInt();//执行command为3的操作,对应FTProtocol中的case 3
dos.flush();//清空缓冲区数据
int files = dis.readInt();//得到目录中文件数量
if (files == ) {//目录中文件为空
System.out.println("no files available on the FTServer");
s.close();//关闭套接字
System.exit(-);//退出程序
}
String[] filenames = new String[files];
for (int i = ; i < files; i++) {
filenames[i] = dis.readUTF();//读取FTProtocol中通过writeUTF(files[i])发来的文件名
System.out.println(i + + "\t\t" + filenames[i]);//输出序号和文件名
} System.out.print("please input your choice:"); BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String c = br.readLine();//读取输入的命令选项 if (c.equalsIgnoreCase("q")) {//若输入'Q'或'q'则退出程序
s.close();//关闭套接字
System.exit();//退出程序
} if (c.equalsIgnoreCase("a")) {//若输入'A'或'a'则下载全部文件
for (int i = ; i < filenames.length; i++) {
System.out.println("filenames[i] = " + filenames[i]);
download(filenames[i]);//循环下载每一个文件
}
s.close();
System.exit();
}
int choice = ;
try {
choice = Integer.parseInt(c);//将字符串转换成整形
} catch (NumberFormatException e) {
System.out.println("your input is wrong");
s.close();
System.exit(-);
} //输入文件对应序号则下载该文件
if (choice >= && choice <= filenames.length) {
download(filenames[choice - ]);
} else {
System.out.println("your input is wrong");
s.close();
System.exit(-);
}
s.close();
System.exit();
} else if (args[].equals("put")) {//上传文件
File f = new File("C:/_Client/" + args[]);//args[2]为文件名
if (f.isFile()) {
upload("C:/_Client/" + args[]);
} else if (f.isDirectory()) {//如果上传的是一个目录
String[] filenames = f.list();//将目录中所有文件存入filenames数组
if (filenames.length == ) {
s.close();
System.out.println("no files available in the directory");
System.exit(-);
}
for (int i = ; i < filenames.length; i++) {//将目录中的文件列表显示
System.out.println(i + + "\t\t" + filenames[i]);
}
System.out.print("please input your choice:");
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String c = br.readLine(); if (c.equalsIgnoreCase("q")) {//若输入'Q'或'q'则退出程序
s.close();//关闭套接字
System.exit();//退出程序
} if (c.equalsIgnoreCase("a")) {//若输入'A'或'a'则上传全部文件
for (int i = ; i < filenames.length; i++) {
String dir = f.getCanonicalPath();//获取文件路径
String tf = null;
if (dir.endsWith(File.separator)) {//如果以分隔符结尾,则直接加上文件名
tf = dir + filenames[i];
} else {//否则加上分隔符再加文件名
tf = dir + File.separator + filenames[i];
}
//此时tf为文件的绝对路径
if(new File(tf).isDirectory()) continue;
upload(tf);
}
s.close();
System.exit();
}
int choice = ;
try {
choice = Integer.parseInt(c);
} catch (NumberFormatException e) {
System.out.println("your input is wrong");
s.close();
System.exit(-);
}
//上传第choice个文件
if (choice >= && choice <= filenames.length) {
String dir = f.getCanonicalPath();
if (dir.endsWith(File.separator)) {
upload(dir + filenames[choice - ]);
} else {
upload(dir + File.separator + filenames[choice - ]);
} } else {
System.out.println("your input is wrong");
s.close();
System.exit(-);
} } else {
s.close();
System.out.println(args[] + " not exists");
System.exit(-);
} s.close();
System.exit(); } } public Socket establish(String server, int port) {
try {
Socket s = new Socket(server, port);
return s;
} catch (Exception e) {
e.printStackTrace();
return null;
}
} public void upload(String filename) throws Exception { File f = new File(filename); if (!f.exists() || !f.isFile()) {
System.out.println("it's wrong, maybe it is not a file or not exists");
System.exit(-);
} byte[] buffer = new byte[];
int rr = ; dos.writeInt();//执行FTProtocol中的上传命令
dos.writeUTF(f.getName());//将文件名传递给FTProtocol
dos.writeLong(f.length());//将文件长度传递给FTProtocol
dos.flush();//清空缓存 FileInputStream fis = new FileInputStream(f);
BufferedInputStream bis = new BufferedInputStream(fis); while ((rr = bis.read(buffer)) != -) {
dos.write(buffer, , rr);
dos.flush();
} bis.close();
fis.close(); } public void download(String filename) throws Exception {
dos.writeInt();//执行FTProtocol中的下载命令
dos.writeUTF(filename);//将要下载的文件名传递给FTProtocol
dos.flush(); //filename = dis.readUTF();
long len = dis.readLong();//获得文件长度 byte[] buffer = new byte[];
long r = ;
int rr = ; //将先下载后的文件输出到C盘的_Client文件夹
FileOutputStream fos = new FileOutputStream("C:/_Client/" + filename);
BufferedOutputStream bos = new BufferedOutputStream(fos); while (r < len) {
if (len - r >= buffer.length) {//若文件未传输的部分大于buffer的长度则每次传输buffer.length的字节
rr = dis.read(buffer, , buffer.length);
} else {//将剩余(小于buffer.length)的数据传输
rr = dis.read(buffer, , (int) (len - r));
}
r = r + rr;
bos.write(buffer, , rr);//将下次传输可接收的字节传递给FTProtocol,rr=-1则传输结束
} bos.close();
fos.close(); System.out.println("download Finished!"); } public static void main(String[] args) throws Exception {
if(args.length==) {
System.out.println("Usage:");
System.out.println("java FTClient host get");
System.out.println("java FTClient host put afile");
System.exit(); }
FTClient ftc = new FTClient();
ftc.args = args;
ftc.start(args[], );//args[0]为host
}
}

FTProtocol.java

 import java.net.Socket;
/*
FTProtocol.java
*/ import java.io.*;
import java.util.*; //与AdvancedSupport都implements IOStrategy,都重写了service()函数
public class FTProtocol implements IOStrategy { @Override
public void service(Socket socket) {
String client = socket.getInetAddress().getHostName() + "(" + socket.getInetAddress().getHostAddress() + ")"; try {
InputStream is = socket.getInputStream();
OutputStream os = socket.getOutputStream();
DataInputStream dis = new DataInputStream(is);
DataOutputStream dos = new DataOutputStream(os); String filename = null;
long len = ;
byte[] buffer = new byte[];
long r = ;
int rr = ; while (true) {
int command = dis.readInt(); // 读取FTClient中通过writeInt()传来的命令
switch (command) {
case : // file upload
filename = dis.readUTF();//接收文件名
len = dis.readLong();//接收文件长度 //将用户上传文件存到FTServer.share目录中
FileOutputStream fos = new FileOutputStream(new File(FTServer.share, filename));
BufferedOutputStream bos = new BufferedOutputStream(fos);
r = ;
rr = ; while (r < len) {
if (len - r >= buffer.length) {
rr = dis.read(buffer, , buffer.length);
} else {
rr = dis.read(buffer, , (int) (len - r));
} r = r + rr;
bos.write(buffer, , rr);
} bos.close();
fos.close();
break;
case : // file download
filename = dis.readUTF();
//dos.writeUTF(filename);
File t = new File(FTServer.share, filename);
//System.out.println("FTServer.share = " + FTServer.share);
dos.writeLong(t.length());//将文件长度传递给FTClient
dos.flush();//清空缓存
FileInputStream fis = new FileInputStream(t);
BufferedInputStream bis = new BufferedInputStream(fis); while ((rr = bis.read(buffer)) != -) {//接收到下次可发送的字节数,-1结束
dos.write(buffer, , rr);
dos.flush();
} bis.close();
fis.close();
break; case : // list files
String[] files = FTServer.share.list();//将share目录下所有文件名存入files数组
List<String> list = new LinkedList<String>();
for(int i=;i<files.length;i++) {
if(new File(FTServer.share, files[i]).isDirectory())
continue;//如果是一个目录则不显示
list.add(files[i]);
} files = list.toArray(new String[]);//将List<String>转换成String[] dos.writeInt(files.length);//将文件数量传给FTClient
dos.flush();//清空缓存
for (int i = ; i < files.length; i++) {
dos.writeUTF(files[i]);//将每一个文件名传给FTClient
}
dos.flush();//清空缓存
break;
}
}
} catch (Exception e) {
if (e instanceof EOFException) {
System.out.println(client + " disconnected");
} else {
e.printStackTrace();
} }
}
}

AdvancedSupport.java

 /*
AdvancedSupport.java
*/ import java.net.*;
import java.io.*;
import java.util.*; //与FTProtocol都implements IOStrategy,都重写了service()函数
public class AdvancedSupport implements IOStrategy {
private ArrayList threads = new ArrayList();//开线程数组
private final int INIT_THREADS = ;//初始线程数
private final int MAX_THREADS = ;//最大线程数
private IOStrategy ios = null;//初始化 //构造函数
public AdvancedSupport(IOStrategy ios) {
this.ios = ios; for (int i = ; i < INIT_THREADS; i++) {
IOThread t = new IOThread(ios);
t.start();
threads.add(t);
}
try {
Thread.sleep();
} catch (Exception e) {
}
} public void service(Socket socket) {
IOThread t = null;
boolean found = false; //顺序找到线程中第一个等待的IOThread,将found置为true并退出循环
for (int i = ; i < threads.size(); i++) {
t = (IOThread) threads.get(i);
if (t.isIdle()) {
found = true;
break;
}
} //若Thread中不存在等待的线程,则新建一个线程并启动
if (!found) {
t = new IOThread(ios);
t.start();
try {
Thread.sleep();
} catch (Exception e) {
}
//将新建线程添加到threads数组中
threads.add(t);
} //将socket赋值为传来的socket参数
t.setSocket(socket);
}
} class IOThread extends Thread {
private Socket socket = null;
private IOStrategy ios = null; public IOThread(IOStrategy ios) {
this.ios = ios;
} public boolean isIdle() {
return socket == null;
} public synchronized void setSocket(Socket socket) {
this.socket = socket;
notify();//唤醒
} public synchronized void run() {
while (true) {
try {
wait();//等待到setSocket执行notify()后,调用service()
ios.service(socket);
socket = null;//service()结束后,套接字置为空
} catch (Exception e) {
e.printStackTrace();
}
}
}
};

IOStrategy.java

 /*
IOStrategy.java
*/ import java.net.*; /*
提供协议策略定义
*/ public interface IOStrategy
{
public void service(Socket socket);
}

NwServer.java

 /*
NwServer.java
*/ import java.net.*; /*
实现网络通信,可以服务于任何应用,没有提供协议,
也就是说NwServer可以适用于任何协议。
*/ public class NwServer
{
private int port = ; //没有处理端口 public NwServer(IOStrategy io, int port) throws Exception {
//它只负责接受客户端的连接请求,建立网络建立(socket连接)
//然后将连接提交给协议处理程序。 this.port = port; ServerSocket server = new ServerSocket(port);
System.out.println("FTServer is ready"); while(true)
{
//接受客户端的连接请求
Socket socket = server.accept(); //获取客户端地址
InetAddress ia = socket.getInetAddress();
System.out.println(ia.getHostName() + "(" + ia.getHostAddress() + ") connected."); //将连接提交给协议处理程序
io.service(socket);
}
}
}

server.properties配置文件:

 share=C:\\_Server
port=

效果展示:

首先看一下客户端和服务器端的存储空间内的文件:

服务器:

[Java] 文件上传下载项目(详细注释)

[Java] 文件上传下载项目(详细注释)

客户端:

[Java] 文件上传下载项目(详细注释)

[Java] 文件上传下载项目(详细注释)

1.编译

[Java] 文件上传下载项目(详细注释)

2.再开一个窗口,分别运行FTServer和FTClient

(1)get命令,得到服务器中的全部文件列表显示(文件夹不显示)

[Java] 文件上传下载项目(详细注释)

(2)·choice输入文件序号则下载对应文件

[Java] 文件上传下载项目(详细注释)

[Java] 文件上传下载项目(详细注释)

  ·choice输入a或A则下载全部文件

[Java] 文件上传下载项目(详细注释)

[Java] 文件上传下载项目(详细注释)

  ·choice输入q或Q则退出

[Java] 文件上传下载项目(详细注释)

(3)put命令,客户端向服务器上传文件(若是一个文件夹则显示文件夹中内容)

·直接上传文件名

[Java] 文件上传下载项目(详细注释)

·上传文件夹

[Java] 文件上传下载项目(详细注释)

choice选项基本和下载时一样:

输入a或A则上传全部文件,输入q或Q则退出,输入文件序号则上传对应文件,不再截图。