Fork me on GitHub

FileZilla使用

搭建个人FTP服务器

使用FileZilla Server轻松搭建个人FTP服务器

安装

百度搜索FileZilla Server,下载到本地并安装

配置

打开安装好的FileZilla Server

Server Address改为127.0.0.1;其他的不用动,点击OK按钮
进入到主界面,然后点击Edit下的Users进入到Users界面

点击add按钮,添加一个用户

选中该用户,设置访问密码

然后在”Shared folders”下设置将要设为FTP目录的文件夹和操作权限
点击add按钮,添加一个共享文件夹,当然这里也可以增加多个,加错了也可以删除(右击要删除的文件夹,点击remove)

这里演示的是把D盘加进来了

设置操作权限(这里全选了)

最后点击界面左下角的Ok按钮,加入该用户

测试FTP

使用本机或者局域网其他电脑,Windows徽标键+R打开运行窗口,输入ftp://为你电脑的IP地址,按回车就弹出了验证窗口。或者打开一个文件夹在地址栏直接输入 ftp://* 并回车。然后输入刚才设置的用户和密码,回车,是不是可以正常访问了?
如果本机测试的话IP可以为127.0.0.1

点击确定后,需要你输入用户名和密码,就是刚才设置的

点击登录后,就可以正常访问了

用户的连接信息在软件运行窗口都可以实时看到

使用FileZilla上传和下载文件

安装

百度搜索FileZilla,下载到本地并安装

配置

打开安装好的FileZilla
如果第一次进入,先把链接建立(IP,用户名,密码,端口(默认是21))

如果之前已经链接上了,那么可以点击这个小按钮登录以前登录过的链接。

1部分是自己本地的路径跟文件,2部分是目标主机上的路径跟文件,3是本地展开后的文件,4是目标主机展开的文件。

上传

在本地文件右击可以上传。

下载

在目标展开文件可以下载。

java代码实现

java实现把文件上传/下载至ftp服务器
功能

  • 实现上传下载功能
  • 记录状态(进度,上传/下载速度,平均速度)
  • 断点续传

代码

不多说,贴代码:
FtpHelper类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
package test;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;
import org.junit.Test;
public class FtpHelper {
private FTPClient ftpClient = new FTPClient();
/**
* 连接到FTP服务器
*
* @param hostname
* 主机名
* @param port
* 端口
* @param username
* 用户名
* @param password
* 密码
* @return 是否连接成功
* @throws IOException
*/
public boolean connect(String hostname, int port, String username,
String password) throws IOException {
ftpClient.connect(hostname, port);
ftpClient.setControlEncoding("GBK");
if (FTPReply.isPositiveCompletion(ftpClient.getReplyCode())) {
if (ftpClient.login(username, password)) {
return true;
}
}
disconnect();
return false;
}
/**
* 从FTP服务器上下载文件,支持断点续传,上传百分比汇报
*
* @param remote
* 远程文件路径
* @param local
* 本地文件路径
* @return 上传的状态
* @throws IOException
*/
public DownloadStatus download(String remote, String local)
throws IOException {
// 设置被动模式
ftpClient.enterLocalPassiveMode();
// 设置以二进制方式传输
ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
DownloadStatus result;
// 检查远程文件是否存在
FTPFile[] files = ftpClient.listFiles(new String(
remote.getBytes("GBK"), "iso-8859-1"));
if (files.length != 1) {
System.out.println("远程文件不存在");
return DownloadStatus.Remote_File_Noexist;
}
long lRemoteSize = files[0].getSize();
File f = new File(local);
long oldTime = 0L;
long nowTime = 0L;
long speed = 0L;
long oldmemory = 0L;
// 本地存在文件,进行断点下载
if (f.exists()) {
long localSize = f.length();
// 判断本地文件大小是否大于远程文件大小
if (localSize >= lRemoteSize) {
System.out.println("本地文件大于远程文件,下载中止");
return DownloadStatus.Local_Bigger_Remote;
}
// 进行断点续传,并记录状态
FileOutputStream out = new FileOutputStream(f, true);
ftpClient.setRestartOffset(localSize);
InputStream in = ftpClient.retrieveFileStream(new String(remote
.getBytes("GBK"), "iso-8859-1"));
byte[] bytes = new byte[1024];
long step = lRemoteSize / 100;
long process = localSize / step;
int c;
oldTime = System.currentTimeMillis();
long startTime = oldTime;
while ((c = in.read(bytes)) != -1) {
out.write(bytes, 0, c);
localSize += c;
long nowProcess = localSize / step;
if (nowProcess > process) {
nowTime = System.currentTimeMillis();
speed = (localSize - oldmemory) / (nowTime - oldTime)
* 1000 / 1024;
oldmemory = localSize;
oldTime = nowTime;
process = nowProcess;
//if (process % 10 == 0)
System.out.println("下载进度:" + process + "%");
System.out.println("下载速度:" + speed + "KB/s");
// TODO 更新文件下载进度,值存放在process变量中
}
}
System.out.println("平均下载速度:" + (localSize) / (System.currentTimeMillis() - startTime)
* 1000 / 1024 + "KB/s");
in.close();
out.close();
boolean isDo = ftpClient.completePendingCommand();
if (isDo) {
result = DownloadStatus.Download_From_Break_Success;
} else {
result = DownloadStatus.Download_From_Break_Failed;
}
} else {
OutputStream out = new FileOutputStream(f);
InputStream in = ftpClient.retrieveFileStream(new String(remote
.getBytes("GBK"), "iso-8859-1"));
byte[] bytes = new byte[1024];
long step = lRemoteSize / 100;
long process = 0;
long localSize = 0L;
int c;
oldTime = System.currentTimeMillis();
long startTime = oldTime;
while ((c = in.read(bytes)) != -1) {
out.write(bytes, 0, c);
localSize += c;
long nowProcess = localSize / step;
if (nowProcess > process) {
nowTime = System.currentTimeMillis();
speed = (localSize - oldmemory) / (nowTime - oldTime)
* 1000 / 1024;
oldmemory = localSize;
oldTime = nowTime;
process = nowProcess;
//if (process % 10 == 0)
System.out.println("下载进度:" + process + "%");
System.out.println("下载速度:" + speed + "KB/s");
// TODO 更新文件下载进度,值存放在process变量中
}
}
System.out.println("平均下载速度:" + (localSize) / (System.currentTimeMillis() - startTime)
* 1000 / 1024 + "KB/s");
in.close();
out.close();
boolean upNewStatus = ftpClient.completePendingCommand();
if (upNewStatus) {
result = DownloadStatus.Download_New_Success;
} else {
result = DownloadStatus.Download_New_Failed;
}
}
return result;
}
/**
* 上传文件到FTP服务器,支持断点续传
*
* @param local
* 本地文件名称,绝对路径
* @param remote
* 远程文件路径,使用/home/directory1/subdirectory/file.ext
* 按照Linux上的路径指定方式,支持多级目录嵌套,支持递归创建不存在的目录结构
* @return 上传结果
* @throws IOException
*/
public UploadStatus upload(String local, String remote) throws IOException {
// 设置PassiveMode传输
ftpClient.enterLocalPassiveMode();
// 设置以二进制流的方式传输
ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
ftpClient.setControlEncoding("GBK");
UploadStatus result;
// 对远程目录的处理
String remoteFileName = remote;
if (remote.contains("/")) {
remoteFileName = remote.substring(remote.lastIndexOf("/") + 1);
// 创建服务器远程目录结构,创建失败直接返回
if (createDirecroty(remote, ftpClient) == UploadStatus.Create_Directory_Fail) {
return UploadStatus.Create_Directory_Fail;
}
}
// 检查远程是否存在文件
FTPFile[] files = ftpClient.listFiles(new String(remoteFileName
.getBytes("GBK"), "iso-8859-1"));
if (files.length == 1) {
long remoteSize = files[0].getSize();
File f = new File(local);
long localSize = f.length();
if (remoteSize == localSize) { // 文件存在
return UploadStatus.File_Exits;
} else if (remoteSize > localSize) {
return UploadStatus.Remote_Bigger_Local;
}
// 尝试移动文件内读取指针,实现断点续传
result = uploadFile(remoteFileName, f, ftpClient, remoteSize);
// 如果断点续传没有成功,则删除服务器上文件,重新上传
if (result == UploadStatus.Upload_From_Break_Failed) {
if (!ftpClient.deleteFile(remoteFileName)) {
return UploadStatus.Delete_Remote_Faild;
}
result = uploadFile(remoteFileName, f, ftpClient, 0);
}
} else {
result = uploadFile(remoteFileName, new File(local), ftpClient, 0);
}
return result;
}
/**
* 断开与远程服务器的连接
*
* @throws IOException
*/
public void disconnect() throws IOException {
if (ftpClient.isConnected()) {
ftpClient.disconnect();
}
}
/**
* 递归创建远程服务器目录
*
* @param remote
* 远程服务器文件绝对路径
* @param ftpClient
* FTPClient对象
* @return 目录创建是否成功
* @throws IOException
*/
public UploadStatus createDirecroty(String remote, FTPClient ftpClient)
throws IOException {
UploadStatus status = UploadStatus.Create_Directory_Success;
String directory = remote.substring(0, remote.lastIndexOf("/") + 1);
if (!directory.equalsIgnoreCase("/")
&& !ftpClient.changeWorkingDirectory(new String(directory
.getBytes("GBK"), "iso-8859-1"))) {
// 如果远程目录不存在,则递归创建远程服务器目录
int start = 0;
int end = 0;
if (directory.startsWith("/")) {
start = 1;
} else {
start = 0;
}
end = directory.indexOf("/", start);
while (true) {
String subDirectory = new String(remote.substring(start, end)
.getBytes("GBK"), "iso-8859-1");
if (!ftpClient.changeWorkingDirectory(subDirectory)) {
if (ftpClient.makeDirectory(subDirectory)) {
ftpClient.changeWorkingDirectory(subDirectory);
} else {
System.out.println("创建目录失败");
return UploadStatus.Create_Directory_Fail;
}
}
start = end + 1;
end = directory.indexOf("/", start);
// 检查所有目录是否创建完毕
if (end <= start) {
break;
}
}
}
return status;
}
/**
* 上传文件到服务器,新上传和断点续传
*
* @param remoteFile
* 远程文件名,在上传之前已经将服务器工作目录做了改变
* @param localFile
* 本地文件File句柄,绝对路径
* @param processStep
* 需要显示的处理进度步进值
* @param ftpClient
* FTPClient引用
* @return
* @throws IOException
*/
public UploadStatus uploadFile(String remoteFile, File localFile,
FTPClient ftpClient, long remoteSize) throws IOException {
UploadStatus status;
// 显示进度的上传
long step = localFile.length() / 100;
long process = 0;
long localreadbytes = 0L;
long oldmemory = 0L;
long oldTime = 0L;
long nowTime = 0L;
long speed = 0L;
RandomAccessFile raf = new RandomAccessFile(localFile, "r");
OutputStream out = ftpClient.appendFileStream(new String(remoteFile
.getBytes("GBK"), "iso-8859-1"));
// 断点续传
if (remoteSize > 0) {
ftpClient.setRestartOffset(remoteSize);
process = remoteSize / step;
raf.seek(remoteSize);
localreadbytes = remoteSize;
}
byte[] bytes = new byte[1024];
int c;
oldTime = System.currentTimeMillis();
long startTime = oldTime;
while ((c = raf.read(bytes)) != -1) {
out.write(bytes, 0, c);
localreadbytes += c;
if (localreadbytes / step != process) {
process = localreadbytes / step;
nowTime = System.currentTimeMillis();
speed = (localreadbytes - oldmemory) / (nowTime - oldTime)
* 1000 / 1024;
oldmemory = localreadbytes;
oldTime = nowTime;
System.out.println("上传进度:" + process + "%");
System.out.println("上传速度:" + speed + "KB/s");
// TODO 汇报上传状态
}
}
System.out.println("平均上传速度:" + (localreadbytes) / (System.currentTimeMillis() - startTime)
* 1000 / 1024 + "KB/s");
out.flush();
raf.close();
out.close();
boolean result = ftpClient.completePendingCommand();
if (remoteSize > 0) {
status = result ? UploadStatus.Upload_From_Break_Success
: UploadStatus.Upload_From_Break_Failed;
} else {
status = result ? UploadStatus.Upload_New_File_Success
: UploadStatus.Upload_New_File_Failed;
}
return status;
}
/**
* 上传测试
*/
@Test
public void uploadTest() {
FtpHelper myFtp = new FtpHelper();
try {
myFtp.connect("127.0.0.1", 21, "zhangsan", "123456");
System.out.println(myFtp.upload("F:/测试文件.rar", "/压缩测试文件.rar"));
myFtp.disconnect();
} catch (IOException e) {
System.out.println("连接FTP出错:" + e.getMessage());
e.printStackTrace();
}
}
/**
* 下载测试
*/
@Test
public void downloadTest() {
FtpHelper myFtp = new FtpHelper();
try {
myFtp.connect("127.0.0.1", 21, "zhangsan", "123456");
System.out.println(myFtp.download("/压缩测试文件.rar", "F:/下载测试文件.rar"));
myFtp.disconnect();
} catch (IOException e) {
System.out.println("连接FTP出错:" + e.getMessage());
e.printStackTrace();
}
}
public enum UploadStatus {
Create_Directory_Fail, // 远程服务器相应目录创建失败
Create_Directory_Success, // 远程服务器闯将目录成功
Upload_New_File_Success, // 上传新文件成功
Upload_New_File_Failed, // 上传新文件失败
File_Exits, // 文件已经存在
Remote_Bigger_Local, // 远程文件大于本地文件
Upload_From_Break_Success, // 断点续传成功
Upload_From_Break_Failed, // 断点续传失败
Delete_Remote_Faild; // 删除远程文件失败
}
public enum DownloadStatus {
Remote_File_Noexist, // 远程文件不存在
Download_New_Success, // 下载文件成功
Download_New_Failed, // 下载文件失败
Local_Bigger_Remote, // 本地文件大于远程文件
Download_From_Break_Success, // 断点续传成功
Download_From_Break_Failed; // 断点续传失败
}
}

注:上传下载操作仅对文件有效,对文件夹无效

jar包要求

需要Jar包为:JUnit4,commons-net-3.3.jar
commons-net-3.3.jar下载点这里

项目地址

项目地址点这里

「真诚赞赏,手留余香」