FTP 概述
文件传输协议(FTP)作为网络共享文件的传输协议,在网络应用软件中具有广泛的应用。FTP的目标是提高文件的共享性和可靠高效地传送数据。
在传输文件时,FTP 客户端程序先与服务器建立连接,然后向服务器发送命令。服务器收到命令后给予响应,并执行命令。FTP 协议与操作系统无关,任何操作系统上的程序只要符合 FTP 协议,就可以相互传输数据。
FTP 协议
相比其他协议,如 HTTP 协议,FTP 协议要复杂一些。与一般的 C/S 应用不同点在于一般的C/S 应用程序一般只会建立一个 Socket 连接,这个连接同时处理服务器端和客户端的连接命令和数据传输。而FTP协议中将命令与数据分开传送的方法提高了效率。
FTP 使用 2 个端口,一个数据端口和一个命令端口(也叫做控制端口)。这两个端口一般是21 (命令端口)和 20 (数据端口)。控制 Socket 用来传送命令,数据 Socket 是用于传送数据。每一个 FTP 命令发送之后,FTP 服务器都会返回一个字符串,其中包括一个响应代码和一些说明信息。其中的返回码主要是用于判断命令是否被成功执行了。
基于FtpClient实现的Ftp连接实现原理层也是通过Socket来实现的
以下是示例代码:
package com.test;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;
import sun.net.ftp.FtpClient;
import sun.net.ftp.FtpProtocolException;
/**
* Java自带的API对FTP的操作
*
* 文件名称:FtpUtil.java
*/
public final class FtpUtil {
private FtpUtil(){}
public final static int BUFF_SIZE = 1024;
/**
* ftp文件上传
* @param connectionString ftp协议链接字符串 ftp://用户名:密码@地址:端口/ 或 ftp://地址:端口/
* @param localFile 本地文件或文件夹
* @param isOver 是否覆盖存在文件
* @throws RuntimeException
*/
@SuppressWarnings("restriction")
public final static void upload(String connectionString, File localFile, boolean isOver) throws RuntimeException
{
if(!localFile.exists()){
throw new RuntimeException("local file is exists!");
}
FtpClient ftpClient = connect(connectionString);
try {
upload(ftpClient, localFile, isOver);
}finally {
try{
ftpClient.close();
}catch(Exception ex){
throw new RuntimeException(ex);
}
}
}
/**
* ftp文件上传
* @param connectionString ftp协议链接字符串 ftp://用户名:密码@地址:端口/ 或 ftp://地址:端口/
* @param remoteFile ftp服务器文件名称
* @param fileStream 待写入文件流
* @param isOver 是否覆盖存在文件
* @throws RuntimeException
*/
@SuppressWarnings("restriction")
public final static void upload(String connectionString, String remoteFile, InputStream fileStream, boolean isOver) throws RuntimeException {
FtpClient ftpClient = connect(connectionString);
try {
if(!"".equals(ftpClient.getStatus(remoteFile)) && !isOver)//是否覆盖文件
return;
try (OutputStream os = ftpClient.putFileStream(remoteFile); InputStream is = fileStream) {
byte[] bytes = new byte[BUFF_SIZE];// 创建一个缓冲区
int c;
while ((c = is.read(bytes)) > 0) {
os.write(bytes, 0, c);
}
}
} catch(Exception ex){
throw new RuntimeException("input stream write fail!", ex);
}finally {
try{
ftpClient.close();
}catch(Exception ex){
throw new RuntimeException(ex);
}
}
}
/**
* 文件上传
* @param ftpClient ftp客户端句柄
* @param localFile 本地文件或文件夹
* @param isOver 是否覆盖存在文件
* @throws RuntimeException
*/
@SuppressWarnings("restriction")
private static void upload(FtpClient ftpClient, File localFile, boolean isOver) throws RuntimeException {
if(localFile.isDirectory()){
try{
try{
ftpClient.changeDirectory(localFile.getName());
}catch(Exception ex){
ftpClient.makeDirectory(localFile.getName());
ftpClient.changeDirectory(localFile.getName());
}
String[] files = localFile.list();
File tempFile;
for (int i = 0; i < files.length; i++) {
tempFile = new File(localFile.getPath()+"\\"+files[i] );
if(tempFile.isDirectory()){
upload(ftpClient, tempFile, isOver);
ftpClient.changeToParentDirectory();
}else{
tempFile = new File(localFile.getPath()+"\\"+files[i]);
streamWrite(ftpClient, tempFile, isOver);
}
}
}catch(Exception ex){
throw new RuntimeException(ex);
}
}else{
streamWrite(ftpClient, localFile, isOver);
}
}
/**
* 文件写入到ftp服务器
* @param ftpClient ftp客户端句柄
* @param localFile 本地文件
* @param isOver 是否覆盖存在文件
* @throws RuntimeException
*/
@SuppressWarnings("restriction")
private static void streamWrite(FtpClient ftpClient, File localFile, boolean isOver) throws RuntimeException{
try{
if(!"".equals(ftpClient.getStatus(localFile.getName())) && !isOver)//是否覆盖文件
return;
try (OutputStream os = ftpClient.putFileStream(localFile.getName());
InputStream is = new FileInputStream(localFile)) {
byte[] bytes = new byte[BUFF_SIZE];// 创建一个缓冲区
int c;
while ((c = is.read(bytes)) > 0) {
os.write(bytes, 0, c);
}
}
}catch(Exception ex){
throw new RuntimeException(ex);
}
}
/**
* 从ftp下载文件到本地
*
* @param filename 服务器上的文件名
* @param newfilename 本地生成的文件名
* @return
* @throws Exception
*/
@SuppressWarnings("restriction")
public static long downloadFile(FtpClient ftpClient, String filename, String newfilename) {
long result = 0;
InputStream is = null;
FileOutputStream os = null;
try {
is = ftpClient.getFileStream(filename);
java.io.File outfile = new java.io.File(newfilename);
os = new FileOutputStream(outfile);
byte[] bytes = new byte[is.available()];
int c;
while ((c = is.read(bytes)) != -1) {
os.write(bytes, 0, c);
result = result + c;
}
} catch (IOException | FtpProtocolException e) {
e.printStackTrace();
} finally {
try {
if (is != null) {
is.close();
}
if (os != null) {
os.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return result;
}
/**
* 取得相对于当前连接目录的某个目录下所有文件列表
*
* @param path
* @return
* @throws FtpProtocolException
*/
@SuppressWarnings("restriction")
public static List<Object> getFileList(FtpClient ftpClient,String path) throws FtpProtocolException{
List<Object> list = new ArrayList<Object>();
DataInputStream dis;
try {
dis = new DataInputStream(ftpClient.nameList( path));
String filename = "";
while((filename = dis.readLine()) != null){
list.add(filename);
}
} catch (IOException e) {
e.printStackTrace();
}
return list;
}
/**
* 连接到ftp服务器
* @param ip ftp服务器地址
* @param port ftp服务器端口
* @param user 登陆ftp服务器用户
* @param password 登陆ftp服务器用户密码
* @param remotePath ftp服务器文件路径
* @return FtpClient
* @throws RuntimeException
*/
@SuppressWarnings("restriction")
private static FtpClient connect(String ip, int port, String user, String password, String remotePath) throws RuntimeException {
FtpClient ftpClient = FtpClient.create();
SocketAddress addr = new InetSocketAddress(ip, port);
try{
ftpClient.connect(addr);
ftpClient.login(user, password.toCharArray());
ftpClient.setBinaryType();
if (remotePath!=null && remotePath.length() != 0) { // 把远程系统上的目录切换到参数path所指定的目录
String[] paths=remotePath.split("/");
for(String path : paths){
if(path.length() == 0)
continue;
try{
ftpClient.changeDirectory(path);
}catch(FtpProtocolException ex){
ftpClient.makeDirectory(path);
ftpClient.changeDirectory(path);
}
}
}
return ftpClient;
}catch(Exception ex){
throw new RuntimeException(ex);
}
}
/**
* 连接到ftp服务器
* @param connectionString 链接字符串
* @return
*/
@SuppressWarnings("restriction")
private static FtpClient connect(String connectionString) throws RuntimeException{
Pattern pattern = Pattern.compile("^ftp://(?:\\S+?:\\S+?@)?\\S+?(?:\\d+?)?");
if(pattern.matcher(connectionString).find()){
String autho = "anonymous", uri = connectionString.substring("ftp://".length()).replace("\\", "/"),
user = "anonymous",pwd = "", ip = "", remotePath = "";
int sp = uri.indexOf("/"), port = 21;
if(sp >= 0){
remotePath = uri.substring(sp);
uri = uri.substring(0, sp);
}
sp = uri.lastIndexOf("@");
if(sp >= 0){
autho = uri.substring(0, sp);
uri = ip = uri.substring(sp + 1);
}
sp = autho.lastIndexOf(":");
if(sp >= 0){
user = autho.substring(0, sp);
pwd = autho.substring(sp + 1);
}
sp = uri.lastIndexOf(":");
if(sp >= 0){
ip = uri.substring(0, sp);
port = Integer.parseInt(uri.substring(sp + 1));
}
return connect(ip, port, user, pwd, remotePath);
}
throw new RuntimeException("connectionString is invalid!");
}
/**
* 断开与ftp服务器连接
*
* @throws IOException
*/
@SuppressWarnings("restriction")
public static boolean closeServer(FtpClient ftpClient) {
try {
if (ftpClient != null) {
//ftpClient.closeServer();
ftpClient.close();
}
System.out.println("已从服务器断开");
return true;
} catch (IOException e) {
e.printStackTrace();
return false;
}
}
@SuppressWarnings("restriction")
public static void main(String[] args) throws FtpProtocolException {
FtpClient ftpClient=connect("192.168.10.11", 22, "test_ftp", "test_123", "/test");
System.out.println("===="+ftpClient.isPassiveModeEnabled());
//upload(ftpClient, new File("E:\\test\\test12.txt"), true);
System.out.println("getFileList: "+getFileList(ftpClient, "/test").get(0));
long ll=downloadFile(ftpClient, "/test/test.txt", "E:\\test\\test.txt");
System.out.println("long : "+ll);
closeServer(ftpClient);
}
}
参考自
http://blog.csdn.net/wochunyang/article/details/53332557