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

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=

效果展示:

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

服务器:

客户端:

1.编译

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

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

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

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

  ·choice输入q或Q则退出

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

·直接上传文件名

·上传文件夹

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

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

[Java] 文件上传下载项目(详细注释)的更多相关文章

  1. 2013第38周日Java文件上传下载收集思考

    2013第38周日Java文件上传&下载收集思考 感觉文件上传及下载操作很常用,之前简单搜集过一些东西,没有及时学习总结,现在基本没啥印象了,今天就再次学习下,记录下自己目前知识背景下对该类问 ...

  2. ssm文件上传下载比较详细的案例

    背景:ssm框架 接下来,我会介绍单文件上传,下载,多文件的上传,下载,使用ajax进行文件的上传下载,和普通的表单提交的文件上传下载. 只要做项目,总是少不了文件的操作,好了废话不多说,直接上代码! ...

  3. Java文件上传下载原理

    文件上传下载原理 在TCP/IP中,最早出现的文件上传机制是FTP.它是将文件由客户端发送到服务器的标准机制. 但是在jsp编程中不能使用FTP方法来上传文件,这是由jsp运行机制所决定的 文件上传原 ...

  4. java文件上传下载组件

    需求: 支持大文件批量上传(20G)和下载,同时需要保证上传期间用户电脑不出现卡死等体验: 内网百兆网络上传速度为12MB/S 服务器内存占用低 支持文件夹上传,文件夹中的文件数量达到1万个以上,且包 ...

  5. java 文件上传下载

    翻新十年前的老项目,文件上传改为调用接口方式,记录一下子~~~ java后台代码: //取配置文件中的上传目录 @Value("${uploadPath}") String pat ...

  6. java文件上传下载

    文件上传首先要引入两个核心包 commons-fileupload-1.2.1.jar commons-io-1.4.jar 下面是对文件上传和下载的一些代码做的一个简单封装,可以方便以后直接使用[使 ...

  7. java 文件上传 下载 总结

    首先引入2个jar ![](http://images2017.cnblogs.com/blog/1128666/201711/1128666-20171101145630498-2084371020 ...

  8. java文件上传下载解决方案

    javaweb上传文件 上传文件的jsp中的部分 上传文件同样可以使用form表单向后端发请求,也可以使用 ajax向后端发请求 1.通过form表单向后端发送请求 <form id=" ...

  9. java文件上传下载 使用SmartUpload组件实现

    使用SmartUpload组件实现(下载jsmartcom_zh_CN.jar) 2017-11-07 1.在WebRoot创建以下文件夹,css存放样式文件(css文件直接拷贝进去),images存 ...

随机推荐

  1. poj 1236 Network of Schools : 求需要添加多少条边成为强连通图 tarjan O(E)

    /** problem: http://poj.org/problem?id=1236 缩点后入度为0的点的总数为需要发放软件的学校个数 缩点后出度为0的点的总数和入度为0的点的总数的最大值为需要增加 ...

  2. Python常用的数据类型

    Python常用的数据类型有很多,今天暂时介绍这三种,int(整数类型).str(字符串).bool(布尔类型)一.int(整数类型)1.不带小数的,integer 的缩写,常用于数据的计算或者大小的 ...

  3. /etc/fstab开机自动挂载设备配置

    第一列:设备名字(路径?) 第二列:设备挂载路径(挂载到的位置) 第三列:分区格式 第四列:文件系统参数(?) 第五列:是否自动dump备份 0   不要    1   定期    2  不定期 第六 ...

  4. (五)、python 函数

    一.函数 def 函数名(参数): ... 函数体 ... 返回值 函数的定义主要有如下要点: def:表示函数的关键字 函数名:函数的名称,日后根据函数名调用函数 函数体:函数中进行一系列的逻辑计算 ...

  5. react初学

    react和vue一样都是mvvm的这种开发模式. 下载js文件 引入HTML文件里 <!DOCTYPE html> <html> <head> <scrip ...

  6. 【Commare中关于理论范畴和技术常用的技术术语】

    1:地址掩码,分类2:OSI/TCP-IP层,归属,作用3:debugg,dispaly具体配置,排错,现象4:原理5:术语 | | = 局域网,广域网 | | = ( (OSPF,RIP,ISIS, ...

  7. 在一台Apache服务器上创建多个站点(不同域名)

    使用不同的域名来区分不同的网站,所有的域名解析都指向同一个 IP 地址.Apache通过在HTTP头中附带的 host参数来判断用户需要访问哪一个网站. 例如要在一台服务器上设置如下两个站点: htt ...

  8. Angular2中使用Jsonp

    除了引入HttpModule模块,还要引入 JsonpModule 模块 import { HttpModule, JsonpModule } from '@angular/http'; Observ ...

  9. 嵌入式C语言查表法

    转自:https://blog.csdn.net/morixinguan/article/details/51799668    作者:Engineer-Bruce_Yang 就像下面的这个表 之前写 ...

  10. go学习笔记-常见命令

    常见命令 go 命令 可以在控制台执行go来查看 go Go is a tool for managing Go source code. Usage: go <command> [arg ...