中午吃完饭上来,再调试程序,再对比了一下。逻辑没区别啊,应该也没问题。可咋就是看不到文件。这时,我便用
filezilla
软件连接到对方FTP服务器上。开始,我怀疑是对方的FTP服务器指定的目录没有读写权限,登上去,手动上传了一个文件,并且成功了。这个时候,便可以排除没有读写权限。
那这又会是什么原因呢?这个时候,没辙,只能求助百度,google了。百度能搜索到的东西真的很少,而且讲的不全,但是这个时候,网上看到一些也碰到过这种情况的。说FTP服务器的模式有
主动模式、被动模式
两种。说的情况也和我碰到的类似。这个时候,心里就认准可能是和服务器设置的模式有关。google了一段
IMPORTANCES<span style="color:#009900;">: By default, the FTP protocol establishes a data connection by opening a port on the client and allows the server connecting to this port. This is called local active mode, but it is usually blocked by firewall so the file transfer may not work. Fortunately, the FTP protocol has another mode, local passive mode, in which a data connection is made by opening a port on the server for the client to connect – and this is not blocked by firewall.
So it is recommended to switch to local passive mode before transferring data, by invoking the methodenterLocalPassiveMode() of the FTPClient class.</span>
这句话,讲的很准确。FTPClient连接FTP服务的时候,Java中
org.apache.commons.net.ftp.FTPClient默认使用的应该是主动模式。所谓
主动模式
:就是指客户端连接服务端的时候,告诉服务端,我们之间要进行通讯,数据交换。我申请开辟一个端口,专门用于我们之间的通信,也即C(client)端主动向S(Server)端发起的请求。
被动模式
就是指,一开始服务一起来,S端变开启一个端口告诉C端,我们之间的通讯就在这个端口下。也就C端被动的接受服务端。
理清了这两种模式之后,感觉还是无从下手。这个时候由于对网络的那一块不熟悉,基本上判断不了主动模式和被动模式,因此,只能求助于我们公司负责网络运维的同事。经过他们的帮忙,从而确认了,对方使用的FTP模式为被动模式。再回到代码中,看到以前的FTP工具类
* 上传文件(主动模式)--默认的模式
* @param ip
* @param port
* @param userName
* @param password
* @param sourceStream
* @param ftpDir
* @param ftpFileName
* @param charset
* @throws FrontEndException
public final static void upload(String ip, int port, String userName, String password, InputStream sourceStream, String ftpDir, String ftpFileName, String charset) throws FrontEndException {
FTPClient ftpClient = new FTPClient();
try {
if (port <= 0)
ftpClient.connect(ip);
else ftpClient.connect(ip, port);
ftpClient.login(userName, password);
//设置上传目录
ftpClient.changeWorkingDirectory(ftpDir);
ftpClient.setBufferSize(1024);
ftpClient.setControlEncoding(charset);
//设置文件类型(二进制)
ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
ftpClient.storeFile(ftpFileName, sourceStream);
} catch (IOException e) {
throw new FrontEndException("上传文件失败", e);
} finally {
try {
ftpClient.disconnect();
} catch (IOException e) {
LOGGER.error("断开ftp连接异常", e);
}心想,或许,真的是和这个模式有关。此时我再仔细Debug了一下。当执行到
ftpClient.storeFile(ftpFileName, sourceStream);我看到返回的是false
,那这个时候基本上可以断定是文件没有上传成功。如果服务器端使用的是被动模式,而我们使用主动模式去上传文件的话。服务器肯定不会接收的
这个时候,感觉问题应该差不多找到了。网上一搜,加上一句设置被动模式的代码
//设置被动模式 ftpClient.enterLocalPassiveMode();
再仔细测试了一下,果然问题就出在这里。解决了。此时正确的代码为
* 被动模式---上传文件
* @param ip
* @param port
* @param userName
* @param password
* @param sourceStream
* @param ftpDir
* @param ftpFileName
* @param charset
* @throws FrontEndException
public final static void uploadPassiveMode(String ip, int port, String userName, String password, InputStream sourceStream, String ftpDir, String ftpFileName, String charset) throws FrontEndException {
FTPClient ftpClient = new FTPClient();
try {
if (port <= 0)
ftpClient.connect(ip);
else ftpClient.connect(ip, port);
boolean login = ftpClient.login(userName, password);
StringBuilder service = new StringBuilder();
service.append("上传FTP【ip="+ip+",port="+port+"】,");
if(login){
LOGGER.info(service.append("登录成功...").toString());
//设置上传目录
ftpClient.changeWorkingDirectory(ftpDir);
ftpClient.setBufferSize(1024);
ftpClient.setControlEncoding(charset);
//设置被动模式
<span style="color:#ff0000;">ftpClient.enterLocalPassiveMode();</span>
//设置文件类型(二进制)
ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
if(ftpClient.storeFile(ftpFileName, sourceStream)){
LOGGER.info(service.append("上传成功...").toString());
} else {
LOGGER.info(service.append("上传失败...").toString());
} else {
LOGGER.info(service.append("登录失败...").toString());
} catch (IOException e) {
throw new FrontEndException("上传文件失败", e);
} finally {
try {
ftpClient.disconnect();
} catch (IOException e) {
LOGGER.error("断开ftp连接异常", e);
}同理,我们在下载对应的结果文件的时候。也需要设置相应的被动模式。
======================附上FTP上传和下载文件时候的步骤===========================
To properly write code to upload files to a FTP server using Apache Commons Net API, the following steps should be followed:
Connect and login to the server.
Enter local passive mode for data connection.
Set file type to be transferred to binary.
Create an InputStream for the local file.
Construct path of the remote file on the server. The path can be absolute or relative to the current working directory.
Call one of the storeXXX()methods to begin file transfer. There are two scenarios:
Using an InputStream-based approach: this is the simplest way, since we let the system does the ins and outs. There is no additional code, just passing the InputStream object into the appropriate method, such as storeFile(String remote, InputStream local) method.
Using an OutputStream-based approach: this is more complex way, but more control. Typically we have to write some code that reads bytes from the InputStream of the local file and writes those bytes into the OutputStream which is returned by the storeXXX() method, such as storeFileStream(String remote) method.
Close the opened InputStream and OutputStream.
Call completePendingCommand() method to complete transaction.
Logout and disconnect from the server.
<span style="color:#ff0000;">NOTES: we should check return value of the storeXXX() and completePendingCommand() method to ensure the upload is completed successfully.</span>
最近在和一个第三方的合作
中
不得已需要使用FTP文件接口。由于FTP Server由对方提供,而且双方背后各自的网络环境都很不单纯等等原因,造成测试环境无法模拟实际情况。测试环境
中
程序一切正常,但是在部署到生产环境之后发现FTP操作不规律性出现“卡死”现象:程序捕获不到任何异常一直卡着,导致轮巡无法正常工作。
为了解决这个问题,我首先考虑的是对于
FTPClient
的使用上没...
代码是一位老哥的原创的https://www.cnblogs.com/tianhyapply/p/3721370.html
我改进了下了一行ftp.enterLocalPassiveMode();
即PASV
模式
(
被动
模式
)
成功上传!
import
java
.io.File;
import
java
.io.FileInputStream;
import org.
apache
.commo...
FTPClient
ftpClient
= new
FTPClient
();
ftpClient
.connect(ftpAddress, ftpPort); // 连接FTP服务器
ftpClient
.login(ftpUserName, ftpPassword);// 登陆FTP服务器
ftpClient
.setControlEncoding("UTF-8");//
中
文支持
ftpClient
.setFileType(
FTPClient
.BINARY_FILE_TYPE)...
最近在做ftp文件上传的时候,开发测试环境上传都没有问题,但是在开发环境缺无法上传,但是也没有报错,纠结了老久。最后看到网上有说
FtpClient
有
主动
模式
和
被动
模式
之分,然后就解决了。
FTPClient
连接FTP服务的时候,
Java
中
org.
apache
.commons.net.ftp.
FTPClient
默认使用的应该是
主动
模式
。所谓
主动
模式
:就是指客户端连接服务端的时候,告诉服务端,...
主动
模式
1. FTP client use TCP port 1026 for command to FTP server command port 21
2. FTP server use TCP port 21 responed to FTP client command port 1026
3. FTP server use TCP port 20 for sending data to FTP client data port 1027 (1026 + 1)
4. FTP client use TCP port 1027 ( 1026 + 1) for data A
ftp上传文件报org.
apache
.commons.net.ftp.FTPConnectionClosedException: Connection closed without indication错误
项目
中
由于ftp做了迁移,代码使用的
ftpclient
登录成功,但是上传文件就报这个错误。
public boolean uploadFile(String ip, int port, String username,
String password, String s
import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.Record;
import com.jfinal.plugin.activerecord.tx.Tx;
import com.jfinal.upload.UploadFile;
import org.
apache
.commons.net.ftp.FTP;
import org.
apache
.commons.net.ftp.
FTPClient
;
import org.
apache
.commons.net.ftp.FTPReply;
import
java
.io.IOException;
import
java
.io.InputStream;
public class FtpController extends Controller {
public void upload() {
UploadFile file = getFile("file");
boolean success = false;
try {
success = uploadToFtp(file.getFileName(), file.getFile());
} catch (IOException e) {
e.printStackTrace();
if (success) {
renderText("上传成功");
} else {
renderText("上传失败");
@Before(Tx.class)
public boolean uploadToFtp(String fileName, File file) throws IOException {
FTPClient
ftp = new
FTPClient
();
ftp.connect("ftp.example.com", 21);
ftp.login("username", "password");
int reply = ftp.getReplyCode();
if (!FTPReply.isPositiveCompletion(reply)) {
ftp.disconnect();
return false;
ftp.setFileType(FTP.BINARY_FILE_TYPE);
ftp.enterLocalPassiveMode();
InputStream input = new FileInputStream(file);
boolean success = ftp.storeFile(fileName, input);
input.close();
ftp.logout();
ftp.disconnect();
if (success) {
Record record = new Record().set("file_name", fileName);
Db.save("file", record);
return success;
这段代码使用了 jfinal 框架和
Apache
Commons Net 库来实现 FTP 文件上传。在 uploadToFtp 方法
中
,我们连接到 FTP 服务器,设置文件类型为二进制,使用
被动
模式
,然后将文件上传到服务器。如果上传成功,我们将文件名保存到数据库
中
。在 upload 方法
中
,我们使用 getFile 方法获取上传的文件,然后调用 uploadToFtp 方法将文件上传到 FTP 服务器。最后,我们根据上传结果返回相应的信息。
关于多层for循环迭代的效率优化问题
会飞的斗篷猿: