这段时间一直在研究java如何访问Ftp,搞了一段时间了,也有一定的了解。故此记录一下。
FTP和TFTP我个人觉得FTP更符合我们程序员的口味,不管是方法命名还是API的详细与否,或者是开发平台的问题,FTP毕竟是Apache的东西,做的就是不错。
其实web开发中一般都会涉及到编码问题,所以web上传下载一定会有中文乱码的问题存在,而FTP对中文的支持比ftp要好多了。
使用ftpClient不需要导入其它jar包,只要你使用java语言开发就行了,而使用FTPClient需要使用commons-net-1.4.1.jar和jakarta-oro-2.0.8.jar,当然jar版本随便你自己。
话不多说,上代码!
FTP服务器的文件目录结构图:
一、FtpClient
FtpClient是属于JDK的包下面的类,但是jdk api并没有对此作介绍,在中文支持上面也有一定的限制。
本段代码中的Ftp服务器的IP地址,用户名和密码均通过SystemConfig.properties文档获取
Ftp_client.java
package com.iodn.util;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ResourceBundle;
import sun.net.TelnetInputStream;
import sun.net.TelnetOutputStream;
import sun.net.ftp.FtpClient;
public class Ftp_client {
//FTP客户端
private FtpClient ftpClient;
private ResourceBundle res=null;
/**
* 连接FTP服务器
* @param path 指定远程服务器上的路径
*/
public Ftp_client(String path){
res = ResourceBundle.getBundle("com.iodn.util.SystemConfig");//获取配置文件propeties文档中的数据
try{
ftpClient=new FtpClient(res.getString("Properties.ftpHostIp"));//如果不想使用配置文件即可将数据写死(如:192.168.1.10)
ftpClient.login(res.getString("Properties.ftpUser"), res.getString("Properties.ftpPassword"));//Ftp服务器用户名和密码
ftpClient.binary();
System.out.println("Login Success!");
if(path.length()!=0){
//把远程系统上的目录切换到参数path所指定的目录(可不用设置,上传下载删除时加Ftp中的全路径即可)
ftpClient.cd(path);
}
}catch(Exception e){
e.printStackTrace();
}
}
/**
* 上传文件
* @param remoteFile
* @param localFile
*/
public boolean upload(String remoteFile, String localFile){
boolean bool=false;
TelnetOutputStream os=null;
FileInputStream is=null;
try{
os=ftpClient.put(remoteFile);
is=new FileInputStream(new File(localFile));
byte[] b=new byte[1024];
int c;
while((c=is.read(b))!=-1){
os.write(b, 0, c);
}
bool=true;
}catch(Exception e){
e.printStackTrace();
System.out.println("上传文件失败!请检查系统FTP设置,并确认FTP服务启动");
}finally{
if(is!=null){
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(os!=null){
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
closeConnect();
}
return bool;
}
/**
* 下载文件
* @param remoteFile 远程文件路径(服务器端)
* @param localFile 本地文件路径(客户端)
*/
public void download(String remoteFile, String localFile) {
TelnetInputStream is=null;
FileOutputStream os=null;
try{
//获取远程机器上的文件filename,借助TelnetInputStream把该文件传送到本地。
is=ftpClient.get(remoteFile);
File file=new File(localFile);
os=new FileOutputStream(file);
byte[] b=new byte[1024];
int c;
while((c=is.read(b))!=-1){
os.write(b,0,c);
}
}catch(Exception e){
e.printStackTrace();
System.out.println("下载文件失败!请检查系统FTP设置,并确认FTP服务启动");
}finally{
if(is!=null){
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(os!=null){
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
closeConnect();
}
}
// 删除文件至FTP通用方法
public void deleteFileFtp(String fileName){
try {
ftpClient.sendServer("dele " + fileName + "\r\n");
} catch (Exception e) {
System.out.println("删除文件失败!请检查系统FTP设置,并确认FTP服务启动");
}finally{
closeConnect();//关闭FTP连接
}
}
/**
* Ftp下载返回byte[]字节数组供前端下载使用
* @param SourceFileName
* @return
* @throws Exception
*/
public byte[] downFileByte(String SourceFileName) throws Exception {
//ftpClient.binary(); //一定要使用二进制模式
TelnetInputStream ftpIn = ftpClient.get(SourceFileName);
ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
byte[] buf = new byte[204800];
int bufsize = 0;
while ((bufsize = ftpIn.read(buf, 0, buf.length)) != -1) {
byteOut.write(buf, 0, bufsize);
}
byte[] return_arraybyte = byteOut.toByteArray();
byteOut.close();
ftpIn.close();
return return_arraybyte;
}
/**
* 关闭FTP连接
*/
public void closeConnect(){
try{
ftpClient.closeServer();
}catch(Exception e){
e.printStackTrace();
}
}
public static void main(String[] args) throws Exception {
Ftp_client test=new Ftp_client("/zhou");
// test.deleteFileFtp("20140412.zip");
// test.upload("20141201.xls", "E:\\201412.xls");//上传文件
//test.download("321.txt", "E:\\111.txt");//下载
test.downFileByte("321.txt");
}
}
二、FTPClient
FTPClient是Apache包下面的类,主要依靠commons-net-1.4.1.jar,支持中文上传下载。
本段代码中的Ftp服务器的IP地址,用户名和密码均通过SystemConfig.properties文档获取
FTPClientHelper.java
package com.iodn.util;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Date;
import java.util.ResourceBundle;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPClientConfig;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;
public class FTPClientHelper {
//FTP客户端
private FTPClient ftpClient;
private ResourceBundle res=null;
/**
* 连接FTP服务器
* @param remotePath //设定当前需要操作的目录
*/
public FTPClientHelper(String remotePath){
res = ResourceBundle.getBundle("com.iodn.util.SystemConfig");
try{
ftpClient=new FTPClient();
ftpClient.connect(res.getString("Properties.ftpHostIp"), 21);//FTP服务器IP地址
ftpClient.login(res.getString("Properties.ftpUser"), res.getString("Properties.ftpPassword"));//FTP服务器用户名和密码
ftpClient.setDataTimeout(120000);
// 下面三行代码必须要,而且不能改变编码格式,否则不能正确下载中文文件
ftpClient.setControlEncoding("GBK");
FTPClientConfig conf = new FTPClientConfig(FTPClientConfig.SYST_UNIX);
conf.setServerLanguageCode("zh");
System.out.println("Login Success!");
int reply=ftpClient.getReplyCode();
if(!FTPReply.isPositiveCompletion(reply)){
ftpClient.disconnect();
ftpClient=null;
}
//转移到设置的目录下
if(remotePath!=null && !remotePath.equals("")){
ftpClient.changeWorkingDirectory(remotePath);
System.out.println("file success");
}
}catch(Exception e){
e.printStackTrace();
}
}
/**
* 上传文件
* @param remoteFile
* @param localFile
*/
public boolean upload( String localFile){
boolean bool=false;
if(ftpClient!=null){
try{
File file=new File(localFile);
String remoteFile=file.getName();
System.out.println(remoteFile);
InputStream is=new FileInputStream(file);
ftpClient.storeFile(remoteFile, is);
is.close();
ftpClient.logout();
bool=true;
}catch(Exception e){
e.printStackTrace();
System.out.println("上传文件失败!请检查系统FTP设置,并确认FTP服务启动");
}finally{
closeConnect();
}
}
return bool;
}
/**
* 下载文件
* @param remoteFile 远程文件路径(服务器端)
* @param fileName 需要下载的文件名
* @param localFile 本地文件路径(客户端)
*/
public boolean download(String fileName, String localPath) {
boolean bool=false;
if(ftpClient!=null){
try{
//ftpClient.changeWorkingDirectory(remoteFile);//转移到FTP服务器目录
FTPFile[] files= ftpClient.listFiles();
for(FTPFile file:files){
if(file.getName().equals(fileName)){
System.out.println("---start---"+System.currentTimeMillis());
String path=localPath+"\\"+file.getName();
System.out.println(path);
File localFile=new File(path);
OutputStream ops=new FileOutputStream(localFile);
ftpClient.retrieveFile(file.getName(), ops);
ops.close();
System.out.println("---ender---"+System.currentTimeMillis());
bool=true;
break;
}
}
}catch(Exception e){
e.printStackTrace();
System.out.println("下载文件失败!请检查系统FTP设置,并确认FTP服务启动");
}finally{
closeConnect();
}
}
return bool;
}
// 删除文件至FTP通用方法
public boolean deleteFileFtp(String fileName){
boolean bool=false;
if(ftpClient!=null){
try {
ftpClient.deleteFile(fileName);
bool=true;
} catch (Exception e) {
System.out.println("删除文件失败!请确定文件是否存在");
}finally{
closeConnect();//关闭FTP连接
}
}
return bool;
}
/**
* 下载文件
* 返回byte[]
* @param fileName 需要下载的文件名
* @return
* @throws Exception
*/
public byte[] downFileByte(String fileName){
byte[] return_arraybyte=null;
if(ftpClient!=null){
try{
FTPFile[] files= ftpClient.listFiles();
for(FTPFile file:files){
if(file.getName().equals(fileName)){
InputStream ins=ftpClient.retrieveFileStream(file.getName());
ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
byte[] buf = new byte[204800];
int bufsize = 0;
while ((bufsize = ins.read(buf, 0, buf.length)) != -1) {
byteOut.write(buf, 0, bufsize);
}
return_arraybyte = byteOut.toByteArray();
byteOut.close();
ins.close();
break;
}
}
}catch(Exception e){
e.printStackTrace();
}finally{
closeConnect();
}
}
return return_arraybyte;
}
/**
* 关闭FTP连接
*/
public void closeConnect(){
try{
ftpClient.disconnect();
}catch(Exception e){
e.printStackTrace();
}
}
public static void main(String[] args) {
FTPClientHelper test=new FTPClientHelper("/zhou");
boolean bool=false;
//bool= test.deleteFileFtp("光路由.doc");
//bool=test.upload("你好.xls", "E:\\你好.xls");//上传文件
//bool=test.download("你好.xls", "D:\\");//下载
//bool=test.downloadToInputStream("/zhou/123.txt");
System.out.println(""+bool);
}
}
三、对web的支持,如何通过jsp页面直接下载
对web的支持,必须要用到serlvet,调用java方法去获取FTP服务器上的文件流。
1、HelpServlet
package com.iodn.servlets;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.iodn.util.FTPClientHelper;
/**
* Servlet implementation class HelpServlet
*/
public class HelpServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public HelpServlet() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("UTF-8");
this.downFtpFile("/HelpDocument", "NJPTPXHelper.chm", request, response);
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
}
/**
* 根据路径下载Ftp中的文件
* @param remoteFile
* @param fileName
* @param request
* @param response
* @throws IOException
*/
public void downFtpFile(String remoteFile,String fileName,HttpServletRequest request,HttpServletResponse response) throws IOException{
// 以流的形式下载文件。
//Ftp_client test=new Ftp_client();
FTPClientHelper ftpClient=new FTPClientHelper(remoteFile);
//test.closeConnect();//关闭连接
byte[] buffer=null;
try {
buffer = ftpClient.downFileByte(fileName);//根据文件名下载FTP服务器上的文件
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// 清空response
response.reset();
response.setContentType("text/html;charset=UTF-8");
// 设置response的Header
// response.addHeader("Content-Disposition", "attachment;filename=" + new String(filename.getBytes("UTF-8"),"ISO-8859-1"));
response.addHeader("Content-Disposition", "attachment;filename=" + new String(fileName.getBytes(),"ISO-8859-1"));
//response.addHeader("Content-Length", "" + fis.length());
OutputStream toClient = new BufferedOutputStream(response.getOutputStream());
response.setContentType("application/octet-stream");
toClient.write(buffer);
toClient.flush();
toClient.close();
}
}
2、JSP页面
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<base href="<%=basePath%>">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>访问Servlet下载帮助文档</title>
</head>
<body leftmargin="0" topmargin="0" style="background-color: white;">
<a href="<span style="color:#ff0000;">HelpServlet</span>" target="_self">
<img src="images/help.png" alt="帮助" width="40" height="40" border="0">
<br>网站帮助
</a>
</body>
</html>
结果: