java中用FTPClient,执行到ftp.storeFile(fileName, inputFile);无反应

package com.aa.test;

import cn.hutool.core.util.StrUtil;
import com.nuctech.platform.tip.constant.TipConstant;
import lombok.extern.slf4j.Slf4j;
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 java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * @Description  ftp操作工具类
 */
@Slf4j
public class FTPClientUtil {

    /**
     * Description: 从FTP服务器下载文件
     * @param url FTP服务器hostname
     * @param port FTP服务器端口
     * @param username FTP登录账号
     * @param password FTP登录密码
     * @param remotePath FTP服务器上的相对路径
     * @param fileName 要下载的文件名
     * @param localPath 下载后保存到本地的路径
	 * @param  menuName 使用menuname 来作为zip包的名称
     * @return
     */
    public static boolean downloadFile(String url, int port, String username, String password, List<String> remotePathes,
                                       List<String> fileName, String localPath,String menuName)
    {
        boolean success = false;
        FTPClient ftp = new FTPClient();
		String zipPath=TipConstant.WORK_DIR+menuName+TipConstant.WORK_DIR_FIX;
		ZipOutputStream zipOutputStream=null;
		FileInputStream fileInputStream=null;
		OutputStream is=null;
		try
        {
        	//创建zip包
			zipOutputStream= new ZipOutputStream(new FileOutputStream(zipPath));
            int reply;

            // 连接FTP服务器
            if (port > -1)
            {
                ftp.connect(url, port);
            }
            else
            {
                ftp.connect(url);
            }
            //登录
            ftp.login(username, password);
            // 设置连接超时时间,5000毫秒
            ftp.setConnectTimeout(5000);
            // 设置中文编码集,防止中文乱码
            ftp.setControlEncoding("UTF-8");
            reply = ftp.getReplyCode();
            if (!FTPReply.isPositiveCompletion(reply)) {
                log.info("下载ftp文件时,未连接到FTP,用户名或密码错误");
                ftp.disconnect();
                return success;
            }else {
                log.info("下载ftp文件时,FTP连接成功");
            }
            for(String remotePath:remotePathes){
				remotePath = new String(remotePath.getBytes("GBK"),"iso-8859-1");
				ftp.changeWorkingDirectory(remotePath);//转移到FTP服务器目录
				FTPFile[] fs = ftp.listFiles();
				for (FTPFile ff : fs)
				{
					if (fileName.contains(ff.getName()))
					{
						File file = new File(localPath);
						if(!file.exists()){
							file.mkdirs();
						}
						File localFile = new File(localPath + "/" + ff.getName());
						//开始从ftp下载图片
						is = new FileOutputStream(localFile);
						ftp.retrieveFile(ff.getName(), is);
						is.close();
						//创建条目
						String name=menuName+File.separator+ff.getName();
						ZipEntry zipEntry = new ZipEntry(name);
						zipOutputStream.putNextEntry(zipEntry);
						//获取文件资源
						String absolutePath = localFile.getAbsolutePath();
						fileInputStream = new FileInputStream(absolutePath);
						//把文件写到zip包中
						byte[] bytes = new byte[1024];
						int read;
						while ((read = fileInputStream.read(bytes)) != -1) {
							zipOutputStream.write(bytes,0,read);
						}
						fileInputStream.close();
					}
				}
			}
            ftp.logout();
            success = true;
        }
        catch (IOException e)
        {
            log.error("从FTP服务器下载文件异常:", e);
        }
        finally
        {
            if (ftp.isConnected())
            {
                try
                {
					is.close();
                	fileInputStream.close();
					zipOutputStream.close();
                    ftp.disconnect();
                }
                catch (IOException e)
                {
                    log.error("下载文件后关闭连接异常:", e);
                }
            }
        }
        return success;
    }

    /**
     * Description: 向FTP服务器上传文件
     * @param url FTP服务器hostname
     * @param port FTP服务器端口,如果默认端口请写-1
     * @param username FTP登录账号
     * @param password FTP登录密码
     * @param path FTP服务器保存目录
     * @param filename 上传到FTP服务器上的文件名
     * @param input 输入流
     * @return 成功返回true,否则返回false
     */
    public static boolean uploadFile(String url, int port, String username, String password, String path,
                                     String filename, InputStream input)
    {
        boolean success = false;
        FTPClient ftp = new FTPClient();
        try
        {
            int reply;

            // 连接FTP服务器
            if (port > -1)
            {
                ftp.connect(url, port);
            }
            else
            {
                ftp.connect(url);
            }

            // 登录FTP
            ftp.login(username, password);
            reply = ftp.getReplyCode();
            if (!FTPReply.isPositiveCompletion(reply))
            {
                ftp.disconnect();
                return success;
            }
			//切换工作路径
			List<String> pathList = getPathList(path);
            for(int i=0;i<pathList.size();i++){
				String dir = new String(pathList.get(i).getBytes("GBK"),"iso-8859-1");
				if(!ftp.changeWorkingDirectory(dir)){
            		if(!ftp.makeDirectory(dir)){
            			log.error("创建文件夹失败");
            			throw new IOException("创建文件夹失败");
					}
					ftp.changeWorkingDirectory(dir);
				}
			}
			ftp.setFileType(FTP.BINARY_FILE_TYPE);
            ftp.storeFile(filename, input);
            input.close();
            ftp.logout();
            success = true;
        }
        catch (IOException e)
        {
            success = false;
            log.error("从FTP服务器上传文件异常", e);
        }
        finally
        {
            if (ftp.isConnected())
            {
                try
                {
                    ftp.disconnect();
                }
                catch (IOException e)
                {
                    log.error("上传文件后关闭连接异常", e);
                }
            }
        }
        return success;
    }
	/**
	 * Description: 向FTP服务器上传xml文件
	 * @param url FTP服务器hostname
	 * @param port FTP服务器端口,如果默认端口请写-1
	 * @param username FTP登录账号
	 * @param password FTP登录密码
	 * @param path FTP服务器保存目录
	 * @param filename 上传到FTP服务器上的文件名
	 * @param input 输入流
	 * @return 成功返回true,否则返回false
	 */
	public static boolean uploadXmlFile(String url, int port, String username, String password, String path,
									 String filename, InputStream input)
	{
		boolean success = false;
		FTPClient ftp = new FTPClient();
		try
		{
			int reply;

			// 连接FTP服务器
			if (port > -1)
			{
				ftp.connect(url, port);
			}
			else
			{
				ftp.connect(url);
			}

			// 登录FTP
			ftp.login(username, password);
			reply = ftp.getReplyCode();
			if (!FTPReply.isPositiveCompletion(reply))
			{
				ftp.disconnect();
				return success;
			}
			String dir = new String(path.getBytes("GBK"),"iso-8859-1");
			if(!ftp.changeWorkingDirectory(dir)){
				if(!ftp.makeDirectory(dir)){
					log.error("创建文件夹失败");
					throw new IOException("创建文件夹失败");
				}
				ftp.changeWorkingDirectory(dir);
			}
			ftp.setFileType(FTP.BINARY_FILE_TYPE);
			ftp.storeFile(filename, input);
			input.close();
			ftp.logout();
			success = true;
		}
		catch (IOException e)
		{
			success = false;
			log.error("从FTP服务器上传文件异常", e);
		}
		finally
		{
			if (ftp.isConnected())
			{
				try
				{
					ftp.disconnect();
				}
				catch (IOException e)
				{
					log.error("上传文件后关闭连接异常", e);
				}
			}
		}
		return success;
	}

    /**
     * <删除FTP上的文件>
     * <远程删除FTP服务器上的录音文件>
     * @param url FTP服务器IP地址
     * @param port FTP服务器端口
     * @param username FTP服务器登录名
     * @param password FTP服务器密码
     * @param remotePath 远程文件路径
     * @param fileName 待删除的文件名
     * @return
     * @see [类、类#方法、类#成员]
     */
    public static boolean deleteFtpFile(String url, int port, String username, String password, String remotePath,
                                        String fileName)
    {
        boolean success = false;
        FTPClient ftp = new FTPClient();
        try
        {
            int reply;

            // 连接FTP服务器
            if (port > -1)
            {
                ftp.connect(url, port);
            }
            else
            {
                ftp.connect(url);
            }

            // 登录
            ftp.login(username, password);
            reply = ftp.getReplyCode();
            if (!FTPReply.isPositiveCompletion(reply))
            {
                ftp.disconnect();
                return success;
            }
            // 转移到FTP服务器目录
			//删除空的文件夹
			String path = remotePath.substring(0, remotePath.lastIndexOf(File.separator));
			remotePath = new String(remotePath.getBytes("GBK"),"iso-8859-1");
            fileName=new String(fileName.getBytes("GBK"),"iso-8859-1");
			if(StrUtil.isBlank(fileName)){
				success=ftp.deleteFile(remotePath);
			}else{
				ftp.changeWorkingDirectory(remotePath);
				//获取当前目录下所有得子文件名称,进行删除
				FTPFile[] ftpFiles = ftp.listFiles();
				for (FTPFile ftpFile : ftpFiles) {
					boolean  isDel=ftp.deleteFile(remotePath + File.separator + ftpFile.getName());
					if(!isDel){
						throw new IOException("删除子文件失败");
					}
				}
				FTPFile[] ftpFiles1 = ftp.listFiles();
				if(null!=ftpFiles1&&ftpFiles1.length!=0){

				}else{
					ftp.changeWorkingDirectory(path);
					ftp.removeDirectory(remotePath);
				}
				success=true;
			}
            ftp.logout();
        }
        catch (IOException e)
        {
            log.error("FTP服务器上删除文件异常", e);
            success = false;
        }
        finally
        {
            if (ftp.isConnected())
            {
                try
                {
                    ftp.disconnect();
                }
                catch (IOException e)
                {
                    log.error("FTP服务器上删除文件后关闭连接", e);
                }
            }
        }
        return success;
    }

	/**
	 * <删除FTP上的文件>
	 * <远程删除FTP服务器上的录音文件>
	 * @param url FTP服务器IP地址
	 * @param port FTP服务器端口
	 * @param username FTP服务器登录名
	 * @param password FTP服务器密码
	 * @param remotePath 远程文件路径
	 * @return
	 * @see [类、类#方法、类#成员]
	 */
    public static boolean delDirPath(String url, int port, String username, String password, String remotePath
									 ) {
		boolean success = false;
		FTPClient ftp = new FTPClient();
		try
		{
			int reply;

			// 连接FTP服务器
			if (port > -1)
			{
				ftp.connect(url, port);
			}
			else
			{
				ftp.connect(url);
			}

			// 登录
			ftp.login(username, password);
			reply = ftp.getReplyCode();
			if (!FTPReply.isPositiveCompletion(reply))
			{
				ftp.disconnect();
				return success;
			}
			String path = remotePath.substring(0, remotePath.lastIndexOf(File.separator));
			remotePath=new String(remotePath.getBytes("GBK"),"iso-8859-1");
			ftp.changeWorkingDirectory(remotePath);
			FTPFile[] ftpFiles = ftp.listFiles();
			if(null!=ftpFiles&&ftpFiles.length!=0){

			}else{
				ftp.changeWorkingDirectory(path);
				ftp.removeDirectory(remotePath);
			}
			ftp.logout();
		}
		catch (IOException e)
		{
			log.error("FTP服务器上删除文件异常", e);
			success = false;
		}
		finally
		{
			if (ftp.isConnected())
			{
				try
				{
					ftp.disconnect();
				}
				catch (IOException e)
				{
					log.error("FTP服务器上删除文件后关闭连接", e);
				}
			}
		}
		return success;

	}


	/**
	 * <删除FTP上的文件>
	 * <远程删除FTP服务器上的录音文件>
	 * @param url FTP服务器IP地址
	 * @param port FTP服务器端口
	 * @param username FTP服务器登录名
	 * @param password FTP服务器密码
	 * @param remotePath 远程文件路径
	 * @param fileName 待删除的文件名
	 * @return
	 * @see [类、类#方法、类#成员]
	 */
	public static boolean delXmlFile(String url, int port, String username, String password, String remotePath,
										String fileName)
	{
		boolean success = false;
		FTPClient ftp = new FTPClient();
		try
		{
			int reply;

			// 连接FTP服务器
			if (port > -1)
			{
				ftp.connect(url, port);
			}
			else
			{
				ftp.connect(url);
			}

			// 登录
			ftp.login(username, password);
			reply = ftp.getReplyCode();
			if (!FTPReply.isPositiveCompletion(reply))
			{
				ftp.disconnect();
				return success;
			}
			remotePath = new String(remotePath.getBytes("GBK"),"iso-8859-1");
			fileName=new String(fileName.getBytes("GBK"),"iso-8859-1");
			//切换工作目录
			ftp.changeWorkingDirectory(remotePath);
			//获取当前目录下所有得子文件名称,进行删除
			boolean  isDel=ftp.deleteFile(remotePath + File.separator + fileName);
			if(!isDel){
				throw new IOException("删除子文件失败");
			}
			success=true;
			ftp.logout();
		}
		catch (IOException e)
		{
			log.error("FTP服务器上删除文件异常", e);
			success = false;
		}
		finally
		{
			if (ftp.isConnected())
			{
				try
				{
					ftp.disconnect();
				}
				catch (IOException e)
				{
					log.error("FTP服务器上删除文件后关闭连接", e);
				}
			}
		}
		return success;
	}

	//分割路径
	public static List<String> getPathList(String path){
		String[] dirs = path.split("/");
		List<String> list = new ArrayList<>();
		String pathname = "";
		for(String str : dirs){
			if(StrUtil.isEmpty(str)){
				continue;
			}
			pathname = pathname + "/" + str;
			list.add(pathname);
		}
		return list;
	}



}

工具类,一找一大把,那就不多说了。我主要说说遇到的问题:连接ftp的客户端,我没有和ftp服务器部署在同一个电脑,如果是同一个电脑,应该也没啥问题。我发现,在我拿到流数据,往ftp文件夹下写图片数据的时候,没有把图片写进去。通过一行一行代码打印日志,排查发现

boolean storeFile = ftp.storeFile(filename, input);方法没有拿到返回值,没有反应。

原因是:

FTP协议有两种工作方式:PORT方式和PASV方式,中文意思为主动式和被动式。

PORT(主动)方式的连接过程是:客户端向服务器的FTP端口(默认是21)发送连接请求,服务器接受连接,建立一条命令链路。当需要传送数据时,客户端在命令链路上用PORT 命令告诉服务器:“我打开了XXXX端口,你过来连接我”。于是服务器从20端口向客户端的 XXXX端口发送连接请求,建立一条数据链路来传送数据。

PASV(被动)方式的连接过程是:客户端向服务器的FTP端口(默认是21)发送连接请 求,服务器接受连接,建立一条命令链路。当需要传送数据时,服务器在命令链路上用PASV 命令告诉客户端:“我打开了XXXX端口,你过来连接我”。于是客户端向服务器的XXXX端口 发送连接请求,建立一条数据链路来传送数据。

解决办法:ftpclient.enterLocalPassiveMode();

/**
	 * Description: 向FTP服务器上传文件
	 *
	 * @param url      FTP服务器hostname
	 * @param port     FTP服务器端口,如果默认端口请写-1
	 * @param username FTP登录账号
	 * @param password FTP登录密码
	 * @param path     FTP服务器保存目录
	 * @param filename 上传到FTP服务器上的文件名
	 * @param input    输入流
	 * @return 成功返回true,否则返回false
	 **/
	public static boolean uploadFile(String url, int port, String username, String password, String path,
									 String filename, InputStream input) {
		log.info("开始调用uploadfile方法");
		boolean success = false;
		FTPClient ftp = new FTPClient();
		try {
			int reply;

			// 连接FTP服务器
			if (port > -1) {
				log.info("开始调用uploadfile方法,url:"+url+",port:"+port);
				ftp.connect(url, port);
			} else {
				log.info("开始调用uploadfile方法else,url:"+url+",port:"+port);
				ftp.connect(url);
			}
			// 登录FTP
			boolean login = ftp.login(username, password);
			log.info("开始调用uploadfile方法,登录FTP,login:"+login);
			reply = ftp.getReplyCode();
			log.info("开始调用uploadfile方法,登录FTP,reply:"+reply);
			if (!FTPReply.isPositiveCompletion(reply)) {
				ftp.disconnect();
				log.info("开始调用uploadfile方法==ftp.disconnect()");
				return success;
			}
			String[] ftpPathDir = path.split("/");
			//切换工作路径
			List<String> pathList = Arrays.asList(ftpPathDir);
			for (int i = 0; i < pathList.size(); i++) {
				String dir = new String(pathList.get(i).getBytes("GBK"), "iso-8859-1");
				if (!ftp.changeWorkingDirectory(dir)) {
					if (!ftp.makeDirectory(dir)) {
						log.error("创建文件夹失败");
					}
					ftp.changeWorkingDirectory(dir);
				}
			}
			boolean setFileType = ftp.setFileType(FTP.BINARY_FILE_TYPE);
			log.info("开始调用uploadfile方法==setFileType:"+setFileType);
			ftp.enterLocalPassiveMode();
			boolean storeFile = ftp.storeFile(filename, input);
			log.info("开始调用uploadfile方法==storeFile:"+storeFile);
			input.close();
			boolean logout = ftp.logout();
			log.info("开始调用uploadfile方法==logout:"+logout);
			success = true;
		} catch (IOException e) {
			success = false;
			log.error("从FTP服务器上传文件异常", e);
		} finally {
			log.error("finally从FTP服务器上传文件异常");
			if (ftp.isConnected()) {
				try {
					ftp.disconnect();
				} catch (IOException e) {
					log.error("上传文件后关闭连接异常", e);
				}
			}
		}
		log.info("调用uploadfile方法结束,结果="+success);
		return success;
	}

### Java 中使用 FTPClient 类的 `retrieveFile` 方法 在 Java 的 Apache Commons Net 库中,`FTPClient` 是用于处理文件传输协议 (FTP) 操作的一个重要类。`retrieveFile(String remote, OutputStream local)` 方法允许从远程服务器下载文件到本地系统。 #### 使用 `retrieveFile` 下载文件的例子 下面是一个完整的例子,展示了如何连接到 FTP 服务器并使用 `retrieveFile` 方法来获取远程文件: ```java import org.apache.commons.net.ftp.FTP; import org.apache.commons.net.ftp.FTPClient; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; public class FtpDownloadExample { public static void main(String[] args) { String server = "ftp.example.com"; int port = 21; String user = "username"; String pass = "password"; FTPClient ftpClient = new FTPClient(); try { ftpClient.connect(server, port); ftpClient.login(user, pass); ftpClient.enterLocalPassiveMode(); // 设置被动模式 // 设置文件类型为二进制 ftpClient.setFileType(FTP.BINARY_FILE_TYPE); String remoteFilePath = "/path/to/remote/file.txt"; String localFilePath = "/path/to/local/directory/"; try (OutputStream outputStream = new FileOutputStream(localFilePath)) { boolean success = ftpClient.retrieveFile(remoteFilePath, outputStream); // 下载文件 if (success) { System.out.println("文件成功下载"); } else { System.out.println("文件下载失败"); } } } catch (IOException ex) { ex.printStackTrace(); } finally { try { if (ftpClient.isConnected()) { ftpClient.logout(); ftpClient.disconnect(); } } catch (IOException ex) { ex.printStackTrace(); } } } } ``` 此代码片段展示了一个基本的工作流程:建立与 FTP 服务器的连接、登录、设置数据传输方式(这里选择了被动模式)、指定要下载的远端路径以及保存至本机的目标位置,并最终关闭会话[^1]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值