FTPClient附件下载不全问题

FTPClient进行附件下载时包下载不全,导致打不开附件问题,例如无法打开文件因为文件格式或扩展名无效,提示如下:

这个问题弄了很久,是开发经理弄了一个月时间都没解决的生产问题,刚入职不久就丢给我处理了。首先,对于生产上的代码我是不敢乱动的。解决办法的第一步是登录用户账号进行该问题的复现,查看日志,是否进行了日志下载,话不多说,先贴上他原来的代码。

Action层:

@RequestMapping("/download")
	public void downloadFile(HttpServletRequest request, HttpServletResponse response) {
		InputStream fis = null;
		try {
			String id = request.getParameter("id");
			System.out.println(id);
			String downloadPath = filepath + id;
			String fileName = request.getParameter("fileName");
			if (id != null) {
				System.out.println("需要下载的文件地址:" + downloadPath);

				try {
					
					fis = FtpHelper.download(id);
					
					byte[] check = new byte[1024];
					if (fis.read(check) == -1) {
						throw new Exception();
					}
					System.out.println("checkend..........1111111111111");
					response.setContentType("application/x-msdownload;charset=UTF-8");
					response.setCharacterEncoding("UTF-8");
					String docName = java.net.URLEncoder.encode(fileName, "UTF-8");
					response.addHeader("Content-Disposition", "attachment; filename=\"" + new String(docName.getBytes("UTF-8"), "UTF-8") + "\"");

					System.out.println("checkend..........222222222222");
					java.io.OutputStream os = response.getOutputStream();
					byte[] b = new byte[1024];
					int i = 0;
					while ((i = fis.read(b)) > 0) {
						os.write(b, 0, i);
						System.out.println("os:" + os.toString());
					}
					System.out.println("checkend..........333333333333333");
					fis.close();
					os.flush();
					os.close();
				} catch (Exception ex) {
					ex.printStackTrace();
					response.setHeader("content-type", "text/html;charset=utf-8");
					String alert = "<script type=\"text/javascript\">alert('没有查询到相应的附件!');history.go(-1);</script>";
					OutputStream outputStream = response.getOutputStream();
					outputStream.write(alert.getBytes("utf-8"));
					outputStream.flush();
				}
			}

		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				response.getOutputStream().close();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

service层

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 com.ibm.process.common.SpringContextHelper;

public class FtpHelper {
	/**
	 * @param ip
	 *            FTP服务器hostname
	 * @param port
	 *            FTP服务器端口
	 * @param username
	 *            FTP登录账号
	 * @param password
	 *            FTP登录密码
	 * @param path
	 *            FTP服务器保存目录
	 * 
	 */
	static Props props = SpringContextHelper.getBean(Props.class);

	private final static int DEFAULT_PORT = 21;

	private static ThreadLocal<FTPClient> FTP_HOLDER = new ThreadLocal<FTPClient>() {
		protected FTPClient initialValue() {
			return null;
		};
	};

	private static boolean connect() throws SocketException, IOException {
		String ip = props.getFtpip();
		int port = props.getFtpport() == 0 ? DEFAULT_PORT : props.getFtpport();
		String username = props.getFtpusername();
		String password = props.getFtppassword();
		FTPClient ftp = FTP_HOLDER.get();
		if (ftp == null) {
			ftp = new FTPClient();
			int reply;
			ftp.connect(ip, port);
			// 连接FTP服务器
			ftp.login(username, password);
			reply = ftp.getReplyCode();
			if (!FTPReply.isPositiveCompletion(reply)) {
				ftp.disconnect();
				return false;
			} else {
				FTP_HOLDER.set(ftp);
				return true;
			}

		} else {
			return true;
		}
	}

	private static boolean changWorkDir() throws IOException {
		String path = props.getFtppath();
		return FTP_HOLDER.get().changeWorkingDirectory(path);

	}

	private static void disconnect() {
		FTPClient ftp = FTP_HOLDER.get();
		if (ftp != null) {
			try {
				System.out.println("ftp.logout()...................");
				//ftp.logout();

				System.out.println("ftp.disconnect()...................");
				ftp.disconnect();
				

				System.out.println("ftp.disconnect()...................end");
			} catch (Exception e) {
				e.printStackTrace();
			}
			FTP_HOLDER.remove();
			System.out.println("ftp.remove()...................end");
		}

	}

	public static InputStream download(String fileName) {

		InputStream is = null;
		try {
			if (connect()) {
				FTPClient ftp = FTP_HOLDER.get();  
				if (changWorkDir()) {
					ftp.setFileType(FTP.BINARY_FILE_TYPE);
					is = ftp.retrieveFileStream(fileName);
					if (is == null) {
						System.out.println("template file " + fileName + " does not exist");
					}else{
						System.out.println("isiscoming.............");
					}
				} else {
					System.out.println("change work directory failure");
				}
			} else {
				System.out.println("ftp logon failure");
			}
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			System.out.println("disconnect.............11111111111111111");
			disconnect();
			System.out.println("disconnect.............222222222222222222");
		}
		return is;
	}

首先,我瞅着他的代码是没有问题的,附件下载成功但打不开,这个只能说明是我们FTP下载过程中下载不完全导致的。排查问题的第一步,在我们每写一句代码的后面打一个日志。方便我们追踪问题在哪遇到坎了。结果发现没问题。

第二步,既然是FTP方式下载文件,那么在我们拿到文件的时候看下文件大小是多少。

好,测试我们发现,拿到的大小就已经比服务器上的大小不一样,小了20KB左右,本地拿到的附件大小当然就跟FTP拿到的一致了,所以,可以定点到是FTP.get()时拿到的文件不一致,故我们就要换掉FTP拿文件的方式了。以下是我重新写的Action、service层,已经测试上生产没有问题出现了。

Action层:

@RequestMapping("/download")
	public void downloadFile1(HttpServletRequest request, HttpServletResponse response) {
		InputStream fis = null;
		try {
			String id = request.getParameter("id");
			System.out.println(id);
			String downloadPath = filepath + id;
			String fileName = request.getParameter("fileName");
			if (id != null) {
				System.out.println("需要下载的文件地址:" + downloadPath);

				try {
					fis = FtpHelper.download1(id);
					
					String docName = java.net.URLEncoder.encode(fileName, "UTF-8");
					System.out.println("====docName==="+docName);
					response.addHeader("Content-Disposition", "attachment; filename=\"" + new String(docName.getBytes("UTF-8"), "UTF-8") + "\"");
					System.out.println("===设置HEAD===");
					
					response.setContentType("application/x-msdownload;charset=UTF-8");
					response.setCharacterEncoding("UTF-8");
					System.out.println("===设置ContentType==");
					OutputStream outputStream = response.getOutputStream();
					System.out.println("===响应流==="+outputStream);
					
					byte[] b = new byte[1024];
					int i = 0;
					System.out.println("===准备写入流===");
					while ((i = fis.read(b)) > 0) {
						outputStream.write(b, 0, i);
						System.out.println("os:" + outputStream.toString());
					}
					System.out.println("===写流结束===");
					
					outputStream.flush();
					outputStream.close();
					fis.close();
					System.out.println("==close===");

				} catch (Exception ex) {
					ex.printStackTrace();
					response.setHeader("content-type", "text/html;charset=utf-8");
					String alert = "<script type=\"text/javascript\">alert('没有查询到相应的附件!');history.go(-1);</script>";
					OutputStream outputStream = response.getOutputStream();
					outputStream.write(alert.getBytes("utf-8"));
					outputStream.flush();
					outputStream.close();
//					ftpClient.logout();
				}
			}

		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				response.getOutputStream().close();
				// ftpClient.logout();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

service层:

package com.ibm.eip.auditsupport.ftp;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.SocketException;

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 com.ibm.process.common.SpringContextHelper;

public class FtpHelper {
	/**
	 * @param ip
	 *            FTP服务器hostname
	 * @param port
	 *            FTP服务器端口
	 * @param username
	 *            FTP登录账号
	 * @param password
	 *            FTP登录密码
	 * @param path
	 *            FTP服务器保存目录
	 * 
	 */
	static Props props = SpringContextHelper.getBean(Props.class);

	private final static int DEFAULT_PORT = 21;

	private static ThreadLocal<FTPClient> FTP_HOLDER = new ThreadLocal<FTPClient>() {
		protected FTPClient initialValue() {
			return null;
		};
	};


	private static void disconnect() {
		FTPClient ftp = FTP_HOLDER.get();
		if (ftp != null) {
			try {
				System.out.println("ftp.logout()...................");
				//ftp.logout();

				System.out.println("ftp.disconnect()...................");
				ftp.disconnect();
				

				System.out.println("ftp.disconnect()...................end");
			} catch (Exception e) {
				e.printStackTrace();
			}
			FTP_HOLDER.remove();
			System.out.println("ftp.remove()...................end");
		}

	}


	public static InputStream download1(String fileName) throws IOException {

		FTPClient ftpClient = null; 
		InputStream is = null;
		try {
			System.out.println("=======进入FTP连接======");
			ftpClient = connect1();
			System.out.println("===ftpClient==="+ftpClient);
			//文件名乱码
			fileName=new String(fileName.getBytes("iso-8859-1"),"utf-8");
			System.out.println("===fileName==="+fileName);
			ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
			ftpClient.enterLocalPassiveMode();
			ftpClient.changeWorkingDirectory(props.getFtppath());
			File localFile = new File(props.getFilepath(),fileName);
			System.out.println("====localFile===="+localFile);
            OutputStream os = new FileOutputStream(localFile);
            System.out.println("====os====="+os);
            ftpClient.retrieveFile(fileName, os);
            System.out.println("====retrieveFile===");
            is = ftpClient.retrieveFileStream(fileName);
            System.out.println("===retrieveFileStream==="+is);
			os.close();
	        System.out.println("=====关闭流=====");
			
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			System.out.println("disconnect.............11111111111111111");
//	         ftpClient.logout();
//			disconnect();
			System.out.println("disconnect.............222222222222222222");
		}
		return is;
	}
	private static FTPClient connect1() throws SocketException, IOException {
		String ip = props.getFtpip();
		int port = props.getFtpport() == 0 ? DEFAULT_PORT : props.getFtpport();
		System.out.println("*****ip*****"+ip);
		System.out.println("*****port***"+port);
		String username = props.getFtpusername();
		String password = props.getFtppassword();
		FTPClient ftp =  new FTPClient();
			int reply;
			ftp.connect(ip, port);
			// 连接FTP服务器
			ftp.login(username, password);
			reply = ftp.getReplyCode();
			System.out.println("====reply====="+reply);
			if (!FTPReply.isPositiveCompletion(reply)) {
				ftp.disconnect();
				System.out.println("****登录FTP失败****");
			} else {
				System.out.println("****登录FTP成功****");
				ftp.setControlEncoding("UTF-8"); // 中文支持
				
				
			}
			System.out.println("====ftp====="+ftp);
			return ftp;
		} 
}

成功了!需要注意的是我是以流的方式来进行写和读的,当从服务器拿下来的时候,就要用

ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE); //设置二进制方式。

            ftpClient.enterLocalPassiveMode();//设置模式,被动还是主动
            ftpClient.changeWorkingDirectory(props.getFtppath());//切换到服务器文件路径底下
            File localFile = new File(props.getFilepath(),fileName);//在服务器上创建该文件
            System.out.println("====localFile===="+localFile);
            OutputStream os = new FileOutputStream(localFile);//创建的该文件
            System.out.println("====os====="+os);yi
            ftpClient.retrieveFile(fileName, os); //创建的该文件写入数据
            System.out.println("====retrieveFile===");
            is = ftpClient.retrieveFileStream(fileName);//写入的数据保留一份以流的方式反馈给Action层接受,用于response响应,反馈给浏览器,剩下的自己再去看下Action层了。

 

 

希望能帮助到大家!

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值