使用Commons net实现FTP上传文件(网络问题无响应解决方案)

       这段时间一直忙着项目开发,没顾上写总结。今天抽点时间对于之前遇到的ftp上传文件无应答的问题总结一下,方便自己以后查看,也方便下个遇到此问题的人能够快速的解决问题。

       使用Apache的开源框架写的一个很简单的ftp上传的demo,如果网络环境稳定的情况下上传文件不会有问题,也能得到服务器文件传完后的响应状态,但是遇到大文件和网络不好的情况下,上传文件时间比较长(半个小时以上),这时执行ftpClient.storeFile("test.ts", in)这句代码会卡在这里,即使文件传完了也不会做出响应,得不到服务器的响应代码就不会继续往下执行,线程也就会一直停在这里。下面是一个简单的文件ftp上传demo:

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;

public class FtpUtil {

	public static void main(String[] args) {

		FTPClient ftpClient = new FTPClient();

		try {
			// 连接指定服务器,默认端口为21
			ftpClient.connect("127.0.0.1");
			System.out.println("connect to server");

			// 获取响应字符串(FTP服务器上可设置)
			String replyString = ftpClient.getReplyString();
			System.out.println("replyString: " + replyString);

			// 获取响应码用于验证是否连接成功
			int reply = ftpClient.getReplyCode();
			if (!FTPReply.isPositiveCompletion(reply)) {
				System.out.println(reply);
				System.exit(1);
			}

			// 设置链接编码,windows主机UTF-8会乱码,需要使用GBK或gb2312编码
			ftpClient.setControlEncoding("GBK");

			// 登录服务器
			boolean login = ftpClient.login("ceshi", "ceshi");
			if (login) {
				System.out.println("登录成功!");
			} else {
				System.out.println("登录失败!");
			}

			// 获取所有文件和文件夹的名字
			FTPFile[] files = ftpClient.listFiles();
			for (FTPFile file : files) {
				if (file.isDirectory()) {
					System.out.println(file.getName() + " 是文件夹");
				}
				if (file.isFile()) {
					System.out.println(file.getName() + " 是文件");
				}
			}

			// 生成InputStream用于上传本地文件
			InputStream in = new FileInputStream("e:\\ceshi.txt");

			// 上传文件
			boolean result = ftpClient.storeFile("test.txt", in);
			if (result) {
				System.out.println("上传成功!");
			}
			in.close();

			// 注销登录
			boolean logout = ftpClient.logout();
			if (logout) {
				System.out.println("注销成功!");
			} else {
				System.out.println("注销失败!");
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			// 关闭链接需要放在finally语句块中
			if (ftpClient.isConnected()) {
				try {
					ftpClient.disconnect();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}
}
解决方案

       遇到这样的问题刚开始不知道怎么回事,经过一番排查后找到了问题的原因,最后给出下面两种解决方法。

       1、这个框架提供了多种上传方法,比如:

org.apache.commons.net.ftp.FTPClient.appendFileStream(String remote) throwsIOException
org.apache.commons.net.ftp.FTPClient.appendFile(String remote,InputStream local) throws IOException
org.apache.commons.net.ftp.FTPClient.storeFileStream(String remote) throwsIOException
org.apache.commons.net.ftp.FTPClient.storeFile(String remote,InputStream local) throws IOException

       可以通过使用直接获取远程目录创建文件、然后拿到输出流将文件写入,这样可以手动控制文件的上传,也可以实现断点续传。这是一种办法,推荐使用这种办法。

       2、这个方案是通过主线程和子线程的方式来实现,将文件上传放在子线程里,主线程负责开启上传子线程和监听子线程文件上传是否完成,如果遇到不响应的情况,主线程会判断文件上传是否完成,如果完成则强制关闭子线程使用的文件流,然后读取新的文件继续开启新的线程来执行上传。



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