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

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

FTServer.java

 1 /*
 2     FTServer.java
 3 */
 4 
 5 import java.util.*;
 6 import java.io.*;
 7 
 8 public class FTServer {
 9     
10     public static File share = null;
11     
12     public static void main(String[] args) throws Exception  {
13         
14         int port = 4321;
15         
16         //加载配置文件
17         Properties p = new Properties();
18         p.load(FTServer.class.getClassLoader().getResourceAsStream("server.properties"));
19         
20         //获取服务器的存储路径
21         share = new File(p.getProperty("share"));
22         
23         if(!share.isDirectory()) {
24             System.out.println("share directory not exists or isn't a directory");
25             System.exit(-4);
26         }
27         
28         //读取服务器与客户机交互的端口号
29         port = Integer.parseInt(p.getProperty("port"));
30         
31         FTProtocol protocol = new FTProtocol();
32         AdvancedSupport as = new AdvancedSupport(protocol);
33         NwServer nw = new NwServer(as,port);
34             
35     }
36 
37 }
View Code

FTClient.java

  1 /*
  2     FTClient.java
  3 */
  4 
  5 import java.net.*;
  6 import java.io.*;
  7 import java.util.*;
  8 
  9 public class FTClient {
 10 
 11     Socket s = null;
 12     DataInputStream dis = null;
 13     DataOutputStream dos = null;
 14 
 15     String[] args = null;
 16 
 17     public void start(String server, int port) throws Exception {
 18         s = establish(server, port);//new一个socket
 19         dis = new DataInputStream(s.getInputStream());
 20         dos = new DataOutputStream(s.getOutputStream());
 21 
 22         if (args[1].equals("get")) {//获取文件
 23             dos.writeInt(3);//执行command为3的操作,对应FTProtocol中的case 3
 24             dos.flush();//清空缓冲区数据
 25             int files = dis.readInt();//得到目录中文件数量
 26             if (files == 0) {//目录中文件为空
 27                 System.out.println("no files available on the FTServer");
 28                 s.close();//关闭套接字
 29                 System.exit(-1);//退出程序
 30             }
 31             String[] filenames = new String[files];
 32             for (int i = 0; i < files; i++) {
 33                 filenames[i] = dis.readUTF();//读取FTProtocol中通过writeUTF(files[i])发来的文件名
 34                 System.out.println(i + 1 + "\t\t" + filenames[i]);//输出序号和文件名
 35             }
 36 
 37             System.out.print("please input your choice:");
 38 
 39             BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
 40             String c = br.readLine();//读取输入的命令选项
 41 
 42             if (c.equalsIgnoreCase("q")) {//若输入'Q'或'q'则退出程序
 43                 s.close();//关闭套接字
 44                 System.exit(0);//退出程序
 45             }
 46 
 47             if (c.equalsIgnoreCase("a")) {//若输入'A'或'a'则下载全部文件
 48                 for (int i = 0; i < filenames.length; i++) {
 49                     System.out.println("filenames[i] = " + filenames[i]);
 50                     download(filenames[i]);//循环下载每一个文件
 51                 }
 52                 s.close();
 53                 System.exit(0);
 54             }
 55             int choice = 0;
 56             try {
 57                 choice = Integer.parseInt(c);//将字符串转换成整形
 58             } catch (NumberFormatException e) {
 59                 System.out.println("your input is wrong");
 60                 s.close();
 61                 System.exit(-2);
 62             }
 63             
 64             //输入文件对应序号则下载该文件
 65             if (choice >= 1 && choice <= filenames.length) {
 66                 download(filenames[choice - 1]);
 67             } else {
 68                 System.out.println("your input is wrong");
 69                 s.close();
 70                 System.exit(-5);
 71             }
 72             s.close();
 73             System.exit(0);
 74         } else if (args[1].equals("put")) {//上传文件
 75             File f = new File("C:/_Client/" + args[2]);//args[2]为文件名
 76             if (f.isFile()) {
 77                 upload("C:/_Client/" + args[2]);
 78             } else if (f.isDirectory()) {//如果上传的是一个目录
 79                 String[] filenames = f.list();//将目录中所有文件存入filenames数组
 80                 if (filenames.length == 0) {
 81                     s.close();
 82                     System.out.println("no files available in the directory");
 83                     System.exit(-8);
 84                 }
 85                 for (int i = 0; i < filenames.length; i++) {//将目录中的文件列表显示
 86                     System.out.println(i + 1 + "\t\t" + filenames[i]);
 87                 }
 88                 System.out.print("please input your choice:");
 89                 BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
 90                 String c = br.readLine();
 91 
 92                 if (c.equalsIgnoreCase("q")) {//若输入'Q'或'q'则退出程序
 93                     s.close();//关闭套接字
 94                     System.exit(0);//退出程序
 95                 }
 96 
 97                 if (c.equalsIgnoreCase("a")) {//若输入'A'或'a'则上传全部文件
 98                     for (int i = 0; i < filenames.length; i++) {
 99                         String dir = f.getCanonicalPath();//获取文件路径
100                         String tf = null;
101                         if (dir.endsWith(File.separator)) {//如果以分隔符结尾,则直接加上文件名
102                             tf = dir + filenames[i];
103                         } else {//否则加上分隔符再加文件名
104                             tf = dir + File.separator + filenames[i];
105                         }
106                         //此时tf为文件的绝对路径
107                         if(new File(tf).isDirectory()) continue;
108                         upload(tf);
109                     }
110                     s.close();
111                     System.exit(0);
112                 }
113                 int choice = 0;
114                 try {
115                     choice = Integer.parseInt(c);
116                 } catch (NumberFormatException e) {
117                     System.out.println("your input is wrong");
118                     s.close();
119                     System.exit(-2);
120                 }
121                 //上传第choice个文件
122                 if (choice >= 1 && choice <= filenames.length) {
123                     String dir = f.getCanonicalPath();
124                     if (dir.endsWith(File.separator)) {
125                         upload(dir + filenames[choice - 1]);
126                     } else {
127                         upload(dir + File.separator + filenames[choice - 1]);
128                     }
129 
130                 } else {
131                     System.out.println("your input is wrong");
132                     s.close();
133                     System.exit(-5);
134                 }
135 
136             } else {
137                 s.close();
138                 System.out.println(args[2] + " not exists");
139                 System.exit(-7);
140             }
141 
142             s.close();
143             System.exit(0);
144 
145         }
146 
147     }
148 
149     public Socket establish(String server, int port) {
150         try {
151             Socket s = new Socket(server, port);
152             return s;
153         } catch (Exception e) {
154             e.printStackTrace();
155             return null;
156         }
157     }
158 
159     public void upload(String filename) throws Exception {
160         
161         File f = new File(filename);
162 
163         if (!f.exists() || !f.isFile()) {
164             System.out.println("it's wrong, maybe it is not a file or not exists");
165             System.exit(-6);
166         }
167 
168         byte[] buffer = new byte[4096];
169         int rr = 0;
170 
171         dos.writeInt(1);//执行FTProtocol中的上传命令
172         dos.writeUTF(f.getName());//将文件名传递给FTProtocol
173         dos.writeLong(f.length());//将文件长度传递给FTProtocol
174         dos.flush();//清空缓存
175 
176         FileInputStream fis = new FileInputStream(f);
177         BufferedInputStream bis = new BufferedInputStream(fis);
178 
179         while ((rr = bis.read(buffer)) != -1) {
180             dos.write(buffer, 0, rr);
181             dos.flush();
182         }
183 
184         bis.close();
185         fis.close();
186 
187     }
188 
189     public void download(String filename) throws Exception {
190         dos.writeInt(2);//执行FTProtocol中的下载命令
191         dos.writeUTF(filename);//将要下载的文件名传递给FTProtocol
192         dos.flush();
193 
194         //filename = dis.readUTF();
195         long len = dis.readLong();//获得文件长度
196 
197         byte[] buffer = new byte[4096];
198         long r = 0;
199         int rr = 0;
200         
201         //将先下载后的文件输出到C盘的_Client文件夹
202         FileOutputStream fos = new FileOutputStream("C:/_Client/" + filename);
203         BufferedOutputStream bos = new BufferedOutputStream(fos);
204 
205         while (r < len) {
206             if (len - r >= buffer.length) {//若文件未传输的部分大于buffer的长度则每次传输buffer.length的字节
207                 rr = dis.read(buffer, 0, buffer.length);
208             } else {//将剩余(小于buffer.length)的数据传输
209                 rr = dis.read(buffer, 0, (int) (len - r));
210             }
211             r = r + rr;
212             bos.write(buffer, 0, rr);//将下次传输可接收的字节传递给FTProtocol,rr=-1则传输结束
213         }
214 
215         bos.close();
216         fos.close();
217         
218         System.out.println("download Finished!");
219 
220     }
221 
222     public static void main(String[] args) throws Exception {
223         if(args.length==0) {
224             System.out.println("Usage:");
225             System.out.println("java FTClient host get");
226             System.out.println("java FTClient host put afile");
227             System.exit(0);
228             
229         }
230         FTClient ftc = new FTClient();
231         ftc.args = args;
232         ftc.start(args[0], 4321);//args[0]为host
233     }
234 }
View Code

FTProtocol.java

  1 import java.net.Socket;
  2 /*
  3     FTProtocol.java
  4 */
  5 
  6 import java.io.*;
  7 import java.util.*;
  8 
  9 //与AdvancedSupport都implements IOStrategy,都重写了service()函数
 10 public class FTProtocol implements IOStrategy {
 11 
 12     @Override
 13     public void service(Socket socket) {
 14         String client = socket.getInetAddress().getHostName() + "(" + socket.getInetAddress().getHostAddress() + ")";
 15 
 16         try {
 17             InputStream is = socket.getInputStream();
 18             OutputStream os = socket.getOutputStream();
 19             DataInputStream dis = new DataInputStream(is);
 20             DataOutputStream dos = new DataOutputStream(os);
 21 
 22             String filename = null;
 23             long len = 0;
 24             byte[] buffer = new byte[4096];
 25             long r = 0;
 26             int rr = 0;
 27 
 28             while (true) {
 29                 int command = dis.readInt(); // 读取FTClient中通过writeInt()传来的命令
 30                 switch (command) {
 31                 case 1: // file upload
 32                     filename = dis.readUTF();//接收文件名
 33                     len = dis.readLong();//接收文件长度
 34                     
 35                     //将用户上传文件存到FTServer.share目录中
 36                     FileOutputStream fos = new FileOutputStream(new File(FTServer.share, filename));
 37                     BufferedOutputStream bos = new BufferedOutputStream(fos);
 38                     r = 0;
 39                     rr = 0;
 40 
 41                     while (r < len) {
 42                         if (len - r >= buffer.length) {
 43                             rr = dis.read(buffer, 0, buffer.length);
 44                         } else {
 45                             rr = dis.read(buffer, 0, (int) (len - r));
 46                         }
 47 
 48                         r = r + rr;
 49                         bos.write(buffer, 0, rr);
 50                     }
 51 
 52                     bos.close();
 53                     fos.close();
 54                     break;
 55                 case 2: // file download
 56                     filename = dis.readUTF();
 57                     //dos.writeUTF(filename);
 58                     File t = new File(FTServer.share, filename);
 59                     //System.out.println("FTServer.share = " + FTServer.share);
 60                     dos.writeLong(t.length());//将文件长度传递给FTClient
 61                     dos.flush();//清空缓存
 62                     FileInputStream fis = new FileInputStream(t);
 63                     BufferedInputStream bis = new BufferedInputStream(fis);
 64 
 65                     while ((rr = bis.read(buffer)) != -1) {//接收到下次可发送的字节数,-1结束
 66                         dos.write(buffer, 0, rr);
 67                         dos.flush();
 68                     }
 69 
 70                     bis.close();
 71                     fis.close();
 72                     break;
 73 
 74                 case 3: // list files
 75                     String[] files = FTServer.share.list();//将share目录下所有文件名存入files数组
 76                     List<String> list = new LinkedList<String>();
 77                     for(int i=0;i<files.length;i++) {
 78                         if(new File(FTServer.share, files[i]).isDirectory()) 
 79                             continue;//如果是一个目录则不显示
 80                         list.add(files[i]);
 81                     }
 82                     
 83                     files = list.toArray(new String[0]);//将List<String>转换成String[]
 84                     
 85                     dos.writeInt(files.length);//将文件数量传给FTClient
 86                     dos.flush();//清空缓存
 87                     for (int i = 0; i < files.length; i++) {
 88                         dos.writeUTF(files[i]);//将每一个文件名传给FTClient
 89                     }
 90                     dos.flush();//清空缓存
 91                     break;
 92                 }
 93             }
 94         } catch (Exception e) {
 95             if (e instanceof EOFException) {
 96                 System.out.println(client + " disconnected");
 97             } else {
 98                 e.printStackTrace();
 99             }
100 
101         }
102     }
103 }
View Code

AdvancedSupport.java

 1 /*
 2     AdvancedSupport.java
 3 */
 4 
 5 import java.net.*;
 6 import java.io.*;
 7 import java.util.*;
 8 
 9 //与FTProtocol都implements IOStrategy,都重写了service()函数
10 public class AdvancedSupport implements IOStrategy {
11     private ArrayList threads = new ArrayList();//开线程数组
12     private final int INIT_THREADS = 10;//初始线程数
13     private final int MAX_THREADS = 100;//最大线程数
14     private IOStrategy ios = null;//初始化
15 
16     //构造函数
17     public AdvancedSupport(IOStrategy ios) {
18         this.ios = ios;
19 
20         for (int i = 0; i < INIT_THREADS; i++) {
21             IOThread t = new IOThread(ios);
22             t.start();
23             threads.add(t);
24         }
25         try {
26             Thread.sleep(300);
27         } catch (Exception e) {
28         }
29     }
30     
31     public void service(Socket socket) {
32         IOThread t = null;
33         boolean found = false;
34         
35         //顺序找到线程中第一个等待的IOThread,将found置为true并退出循环
36         for (int i = 0; i < threads.size(); i++) {
37             t = (IOThread) threads.get(i);
38             if (t.isIdle()) {
39                 found = true;
40                 break;
41             }
42         }
43         
44         //若Thread中不存在等待的线程,则新建一个线程并启动
45         if (!found) {
46             t = new IOThread(ios);
47             t.start();
48             try {
49                 Thread.sleep(30);
50             } catch (Exception e) {
51             }
52             //将新建线程添加到threads数组中
53             threads.add(t);
54         }
55         
56         //将socket赋值为传来的socket参数
57         t.setSocket(socket);
58     }
59 }
60 
61 class IOThread extends Thread {
62     private Socket socket = null;
63     private IOStrategy ios = null;
64 
65     public IOThread(IOStrategy ios) {
66         this.ios = ios;
67     }
68 
69     public boolean isIdle() {
70         return socket == null;
71     }
72 
73     public synchronized void setSocket(Socket socket) {
74         this.socket = socket;
75         notify();//唤醒
76     }
77 
78     public synchronized void run() {
79         while (true) {
80             try {
81                 wait();//等待到setSocket执行notify()后,调用service()
82                 ios.service(socket);
83                 socket = null;//service()结束后,套接字置为空
84             } catch (Exception e) {
85                 e.printStackTrace();
86             }
87         }
88     }
89 };
View Code

IOStrategy.java

 1 /*
 2     IOStrategy.java
 3 */
 4 
 5 import java.net.*;
 6 
 7 /*
 8     提供协议策略定义
 9 */
10 
11 public interface IOStrategy
12 {
13     public void service(Socket socket);
14 }
View Code

NwServer.java

 1 /*
 2     NwServer.java
 3 */
 4 
 5 import java.net.*;
 6 
 7 /*
 8     实现网络通信,可以服务于任何应用,没有提供协议,
 9     也就是说NwServer可以适用于任何协议。
10 */
11 
12 public class NwServer
13 {
14     private int port = 4321;  //没有处理端口
15     
16     public NwServer(IOStrategy io, int port) throws Exception {
17         //它只负责接受客户端的连接请求,建立网络建立(socket连接)
18         //然后将连接提交给协议处理程序。
19         
20         this.port = port;
21 
22         ServerSocket server = new ServerSocket(port);
23         System.out.println("FTServer is ready");
24 
25         while(true)
26         {
27             //接受客户端的连接请求
28             Socket socket = server.accept();
29             
30             //获取客户端地址
31             InetAddress ia = socket.getInetAddress();
32             System.out.println(ia.getHostName() + "(" + ia.getHostAddress() + ") connected."); 
33             
34             //将连接提交给协议处理程序
35             io.service(socket);
36         }
37     }
38 }
View Code

server.properties配置文件:

1 share=C:\\_Server
2 port=4321
View Code

效果展示:

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

服务器:

客户端:

1.编译

 

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

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

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

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

  ·choice输入q或Q则退出

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

·直接上传文件名

·上传文件夹

 

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

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

posted @ 2017-02-23 03:10  Strawberry丶  阅读(384)  评论(0编辑  收藏  举报