Java實現FTP文件上傳和下載

目錄
一、背景
二、maven依賴
三、FTP工具類
3.1、主動模式(PORT)
3.2、被動模式(PASV)
四、驗證
4.1、dos下操作FTP
4.2、FTP文件上傳
4.3、FTP文件下載
一、背景
  我在之前的文章(Java實現文件上傳和下載)裏講過非FTP文件的上傳和下載,今天我們來講一下FTP文件上傳和下載,本文測試過程中Spring Boot 版本爲2.5.2,commons-net 版本爲3.8.0,JDK環境爲 1.8。本文是在window環境下完成的,因爲本機環境的複雜性,是把本機的防火牆關閉了的(不然dos登錄後操作不了,或者上傳下載超時)。

二、maven依賴
pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.2</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>

<groupId>com.alian</groupId>
<artifactId>ftp</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>ftp</name>
<description>java實現FTP文件上傳下載</description>

<properties>
<java.version>1.8</java.version>
</properties>

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>

<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.12.0</version>
</dependency>

<dependency>
<groupId>commons-net</groupId>
<artifactId>commons-net</artifactId>
<version>3.8.0</version>
</dependency>

<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.14</version>
</dependency>

<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>compile</scope>
</dependency>

</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>

</project>
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
三、FTP工具類
  本工具類中包含四個方法,實例化方法,上傳文件,下載文件,及關閉連接方法。

ApacheFtpClient.java

package com.alian.ftp.utils;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;

import java.io.*;

@Slf4j
public class ApacheFtpClient {

private FTPClient ftpClient;

/**
* 實例化
*
* @param hostName FTP服務器地址
* @param port FTP服務器端口
* @param userName FTP登錄賬戶
* @param password FTP登錄密碼
* @throws IOException
*/
public ApacheFtpClient(String hostName, int port, String userName, String password) throws IOException {
ftpClient = new FTPClient();
//設置傳輸命令的超時
ftpClient.setDefaultTimeout(20000);//毫秒
//設置兩個服務連接超時時間
ftpClient.setConnectTimeout(10000);//毫秒
//被動模式下設置數據傳輸的超時時間
ftpClient.setDataTimeout(15000);//毫秒
//連接FTP
ftpClient.connect(hostName, port);
//更加賬戶密碼登錄服務
ftpClient.login(userName, password);
//被動模式(需要設置在連接之後,尤其linux環境)
ftpClient.enterLocalPassiveMode();
}

/**
* FTP上傳文件
*
* @param remoteUploadDirectory 要上傳的目錄(FTP服務器上的目錄)
* @param localUploadFilePathName 本地上傳文件的完整路徑(本地路徑)
* @return
*/
public Pair<Boolean, String> uploadFile(String remoteUploadDirectory, String localUploadFilePathName) {
FileInputStream fis = null;
try {
// 如果不能進入dir下,說明此目錄不存在!
System.out.println("FTP響應碼:"+ftpClient.getReplyCode());
System.out.println("FTP響應信息:"+ftpClient.getReplyString());
if (!ftpClient.changeWorkingDirectory(remoteUploadDirectory)) {
log.info("沒有目錄:{}", remoteUploadDirectory);
if (!ftpClient.makeDirectory(remoteUploadDirectory)) {
log.info("創建文件目錄【{}】 失敗!", remoteUploadDirectory);
return Pair.of(false, "創建文件目錄【" + remoteUploadDirectory + "】 失敗");
}
}
//進入文件目錄
ftpClient.changeWorkingDirectory(remoteUploadDirectory);
//創建文件流
fis = new FileInputStream(new File(localUploadFilePathName));
//設置上傳目錄
ftpClient.setBufferSize(1024);
//設置文件類型(二進制)
ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
//FTP服務器上最終的名字
String uploadFileName = localUploadFilePathName.substring(localUploadFilePathName.lastIndexOf(File.separator) + 1);
//文件上傳
boolean b = ftpClient.storeFile(uploadFileName, fis);
int replyCode = ftpClient.getReplyCode();
log.info("上傳文件響應碼:{}", replyCode);
log.info("上傳文件響應信息:{}", ftpClient.getReplyString());
return Pair.of(b, b ? "上傳成功" : "上傳失敗");
} catch (Exception e) {
log.error("FTP上傳文件異常!:", e);
return Pair.of(false, "上傳文件異常");
} finally {
try {
if (fis != null) {
fis.close();
}
} catch (IOException e) {
log.error("關閉流發生異常!", e);
}
}
}

/**
* FTP文件下載
*
* @param remoteDownloadDirectory 要下載的目錄(FTP服務器目錄)
* @param localDirectory 本地下載文件路徑
* @param downloadFileName 下載的文件名
* @return
*/
public Pair<Boolean, String> downloadFile(String remoteDownloadDirectory, String localDirectory, String downloadFileName) {
OutputStream out = null;
try {
if (StringUtils.isBlank(downloadFileName)) {
return Pair.of(false, "要下載的文件不能爲空");
}
//工作目錄切換到下載文件的目錄下
if (!ftpClient.changeWorkingDirectory(remoteDownloadDirectory)) {
log.info("目錄不存在:{}", remoteDownloadDirectory);
return Pair.of(false, "目錄不存在");
}
//獲取目錄下所有文件
FTPFile[] files = ftpClient.listFiles();
if (files.length < 1) {
return Pair.of(false, "目錄爲空");
}
boolean fileExist = false;
boolean downloadFlag = false;
//遍歷文件列表
for (FTPFile ftpFile : files) {
String localFile = localDirectory + File.separator + downloadFileName;
//是否存在要下載的文件
if (downloadFileName.equals(ftpFile.getName())) {
fileExist = true;
out = new FileOutputStream(localFile);
//下載
downloadFlag = ftpClient.retrieveFile(downloadFileName, out);
int replyCode = ftpClient.getReplyCode();
log.info("下載文件響應碼:{}", replyCode);
break;
}
}
if (!fileExist) {
return Pair.of(false, "FTP服務器上文件不存在");
}
return Pair.of(downloadFlag, downloadFlag ? "下載成功" : "下載失敗");
} catch (Exception e) {
log.error("FTP下載文件異常!:", e);
return Pair.of(false, "下載文件異常");
} finally {
try {
if (out != null) {
out.flush();
out.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}

public void close() {
try {
if (ftpClient != null && ftpClient.isConnected()) {
ftpClient.disconnect();
}
} catch (IOException e) {
e.printStackTrace();
}
}

}
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
  注意構造方法中的調用,FTP協議有兩種工作方式:

// 被動模式(需要設置在連接之後,尤其linux環境)
ftpClient.enterLocalPassiveMode();
1
2
  如果是windows環境上傳下載沒啥問題,如果是linux環境,可能端口未開放就需要我們使用這個被動模式,而且是登錄之後,不然你調用 listFiles() 方法可能就是返回null了。

  如果你是要設置編碼的話,你需要在你連接,登錄之前進行設置。不然就是無效,FTP服務器默認的編碼是 ISO-8859-1 。所以你上傳和下載時,不管是文件目錄,或者文件名,或者文件的編碼都要進行相應的統一轉換,我這裏就沒有改服務器上編碼格式了。

//被動模式(需要設置在連接之前)
ftpClient.setControlEncoding("UTF-8");
1
2
3.1、主動模式(PORT)
  主動模式的FTP是指服務器主動連接客戶端的數據端口。

FTP客戶端隨機開啓一個大於1024的端口N向服務器的21號端口發起連接,同時開放N+1號端口進行監聽,然後發送PORT命令到FTP服務器,告知是主動模式
FTP服務器給客戶端的命令端口返回一個ACK的應答碼
FTP客戶端發出數據傳輸的指令
FTP服務器發起一個從它自己的數據端口(一般是20端口)到客戶端先前指定的數據端口(N+1)的連接
FTP客戶端返回一個ACK後,進行數據傳輸
3.2、被動模式(PASV)
  被動模式的FTP是指服務器被動地等待客戶端連接自己的數據端口。

FTP客戶端隨機開啓一個大於1024的端口N向服務器的21號端口發起連接,同時會開啓N+1號端口。然後向服務器發送PASV命令,告知是被動模式
FTP服務器收到命令後,會開放一個大於1024的端口P進行監聽,然後用PORT命令通知客戶端,服務端的數據端口是P
FTP客戶端發出數據傳輸的指令,會通過N+1號數據端口連接服務器的端口P
FTP服務器給客戶端的數據端口返回一個ACK的應答碼,然後在兩個端口之間進行數據傳輸
四、驗證
4.1、dos下操作FTP
  如果你是window環境下操作FTP,建議關閉防火牆操作。
輸入命令:

#在cmd命令提示符下輸入(ftp加FTP服務器地址)
ftp 192.168.0.151
#根據提示輸入用戶名
Alian
#根據提示輸入登錄密碼
Alian@1223
1
2
3
4
5
6
本文登錄後的文件列表:


4.2、FTP文件上傳
@Test
public void upload() throws IOException {
ApacheFtpClient apacheFtpClient = new ApacheFtpClient("192.168.0.151", 21, "Alian", "Alian@1223");
Pair<Boolean, String> pair = apacheFtpClient.uploadFile("apacheFTP", "C:\\myFile\\CSDN\\result.png",);
log.info("上傳返回結果:{}", pair);
apacheFtpClient.close();
}
1
2
3
4
5
6
7
運行結果:

17:16:55.830 [main] INFO com.alian.ftp.utils.ApacheFtpClient - 上傳文件響應碼:226
17:16:55.835 [main] INFO com.alian.ftp.service.TestApacheFtpService - 上傳返回結果:(true,上傳成功)
1
2
登錄FTP服務器上查看文件如下:


4.3、FTP文件下載
@Test
public void download() throws IOException {
ApacheFtpClient apacheFtpClient = new ApacheFtpClient("192.168.0.151", 21, "Alian", "Alian@1223");
Pair<Boolean, String> pair = apacheFtpClient.downloadFile("apacheFTP", "C:\\myFile\\download", "result.png");
log.info("下載返回結果:{}", pair);
apacheFtpClient.close();
}
1
2
3
4
5
6
7
運行結果:

17:20:37.126 [main] INFO com.alian.ftp.utils.ApacheFtpClient - 下載文件響應碼:226
17:20:37.130 [main] INFO com.alian.ftp.service.TestApacheFtpService - 下載返回結果:(true,下載成功)
1
2
進入到我們本地下載的目錄,結果如下:

————————————————
版權聲明:本文爲CSDN博主「嘉禾嘉寧papa」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/Alian_1223/article/details/121315158

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章