FTP断点上传下载

断点上传和下载工具类,包括目录文件的创建、判断、ftp连接等,直接copy就可用。使用FileZilla Server,需要用commons.net的jar包,到官网下载。最大的坑就是编码问题,在window默认GBK,ftp Server从09.41后默认utf-8,百度一大堆,自行查找。最佳的解决在此文章ftpConnect()方法中,请阅读。

package com.utils;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.io.UnsupportedEncodingException;
import java.net.SocketException;
import java.util.HashMap;

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;

public class FtpUtils {
    private static FTPClient ftpClient = new FTPClient();
    private static String encoding = System.getProperty("file.encoding");
    private static HashMap<String, String> map;
    private static String directory;

    /**
     * 创建多层目录文件,如果有ftp服务器已存在该文件,则不创建,如果无,则创建
     * 
     * @param remote
     * @return
     * @throws IOException
     */
    public static ResponseResult CreateDirecroty(String remote, String filename)
            throws IOException {
        ResponseResult checkRemoteFile;
        checkRemote(remote);
        // 如果远程目录不存在,则递归创建远程服务器目录
        if (!directory.equalsIgnoreCase("/")
                && !changeWorkingDirectory(new String(directory), ftpClient)) {
            int start = 0;
            int end = 0;
            if (directory.startsWith("/")) {
                start = 1;
            } else {
                start = 0;
            }
            end = directory.indexOf("/", start);
            String path = "";
            String paths = "";
            while (true) {
                // 对目录进行转码
                String subDirectory = new String(remote.substring(start, end)
                        .getBytes(encoding), "iso-8859-1");
                path = path + "/" + subDirectory;
                checkRemoteFile = checkRemoteFile(filename, ftpClient);
                if (checkRemoteFile.getStatus() != 200) {
                    if (makeDirectory(subDirectory, ftpClient)) {
                        changeWorkingDirectory(subDirectory, ftpClient);
                    } else {
                        System.out.println("创建目录[" + subDirectory + "]失败");
                        changeWorkingDirectory(subDirectory, ftpClient);
                    }
                } else {
                    changeWorkingDirectory(subDirectory, ftpClient);
                }

                paths = paths + "/" + subDirectory;
                start = end + 1;
                end = directory.indexOf("/", start);
                // 检查所有目录是否创建完毕
                if (end <= start) {
                    break;
                }
            }
        } else {
            // 检查服务器文件是否存在
            checkRemoteFile = checkRemoteFile(filename, ftpClient);
        }
        return checkRemoteFile;
    }

    private static void checkRemote(String remote) {
        char c = remote.charAt(remote.length() - 1);
        if ("/".charAt(0) == c) {
            directory = remote;
        } else {
            directory = remote + "/";
        }
    }

    /**
     * 创建目录
     * 
     * @param dir
     * @param ftp
     * @return
     */
    public static boolean makeDirectory(String dir, FTPClient ftp) {
        boolean flag = true;
        try {
            flag = ftp.makeDirectory(dir);
            if (flag) {
                System.out.println("创建文件夹" + dir + " 成功!");
            } else {
                System.out.println("创建文件夹" + dir + " 失败!");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return flag;
    }

    /**
     * 判断ftp服务器文件是否存在
     * 
     * @param filename
     * @param ftp
     * @return
     * @throws IOException
     */
    public static ResponseResult checkRemoteFile(String filename, FTPClient ftp)
            throws IOException {
        FTPFile[] ftpFileArr = ftp.listFiles(filename);

        for (FTPFile ftpFile : ftpFileArr) {
            if (ftpFileArr.length > 0) {
                System.out.println(ftpFile.getSize());
                return ResponseResult.build(200, "存在");
            }
        }

        return ResponseResult.build(300, "不存在");
    }

    /**
     * 改变目录路径
     * 
     * @param directory
     * @param ftp
     * @return
     */
    public static boolean changeWorkingDirectory(String directory, FTPClient ftp) {
        boolean flag = true;
        try {
            flag = ftp.changeWorkingDirectory(directory);
            if (flag) {
                System.out.println("进入文件夹" + directory + " 成功!");
            } else {
                System.out.println("进入文件夹" + directory + " 失败!");
            }
        } catch (IOException ioe) {
            ioe.printStackTrace();
        }
        return flag;
    }

    /**
     * 检查本地文件是否存在
     * 
     * @param localPath
     *            本地文件路径
     * @return
     */
    public static long checkLocalFile(String localPath) {
        File file = new File(localPath);
        if (file.exists()) {
            return file.length();
        }
        return 0;

    }

    /**
     * Description: 从FTP服务器下载文件
     * 
     * @param url
     *            FTP服务器hostname
     * @param port
     *            FTP服务器端口
     * @param username
     *            FTP登录账号
     * @param password
     *            FTP登录密码
     * @param remotePath
     *            FTP服务器上的相对路径
     * @param fileName
     *            下载的文件名
     * @param localPath
     *            下载后保存到本地的路径
     * @return
     */
    public static boolean downloadFile(String fileName, String localPath) {
        boolean status = false;
        try {

            ftpConnect();
            // 转移到FTP服务器目录至指定的目录下
            ftpClient.changeWorkingDirectory(new String(map.get("remotePath")
                    .getBytes(encoding), "iso-8859-1"));
            // 获取本地文件大小
            long checkLocalFile = checkLocalFile(localPath + "/" + fileName);
            // 获取远程文件
            String remotePathFile = map.get("remotePath") + "/" + fileName;
            FTPFile[] fs = ftpClient.listFiles(new String(remotePathFile
                    .getBytes(encoding), "iso-8859-1"));
            // 判断本地文件是否存在
            if (checkLocalFile != 0) {
                System.out.println("本地文件已存在");
                // 存在,则进行断点下载
                for (FTPFile ff : fs) {
                    if (ff.getName().equals(fileName)) {
                        checkLocalFile = downBreakPoint(localPath,
                                checkLocalFile, ff);
                    }
                    status = true;
                }
            } else {
                // 直接下载
                for (FTPFile ff : fs) {
                    if (ff.getName().equals(fileName)) {
                        File localFile = new File(localPath + "/"
                                + ff.getName());
                        OutputStream out = new FileOutputStream(localFile);
                        ftpClient.retrieveFile(ff.getName(), out);
                    }
                }
                ftpClient.completePendingCommand();
                status = true;
            }
            ftpClient.logout();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (ftpClient.isConnected()) {
                try {
                    ftpClient.disconnect();
                } catch (IOException ioe) {
                }
            }
        }
        return status;
    }

    /**
     * 断点下载代码段
     * @param localPath
     * @param checkLocalFile
     * @param ff
     * @return
     * @throws FileNotFoundException
     * @throws IOException
     * @throws UnsupportedEncodingException
     */
    private static long downBreakPoint(String localPath, long checkLocalFile,
            FTPFile ff) throws FileNotFoundException, IOException,
            UnsupportedEncodingException {
        // 获得远程文件大小
        long RemoteSize = ff.getSize();
        if (RemoteSize <= checkLocalFile) {
            System.out.println("文件已下载");
        } else {
            // 断点下载
            File localFile = new File(localPath + "/" + ff.getName());
            OutputStream out = new FileOutputStream(localFile);
            InputStream in = ftpClient.retrieveFileStream(((new String(ff
                    .getName().getBytes(encoding), "iso-8859-1"))));

            ftpClient.setRestartOffset(checkLocalFile);

            byte[] bytes = new byte[1024];
            // long step = RemoteSize / 100;
            // long process = checkLocalFile / step;
            int c;
            while ((c = in.read(bytes)) != -1) {
                out.write(bytes, 0, c);
                checkLocalFile += c;
                // long nowProcess = checkLocalFile /
                // step;
                /*
                 * if (nowProcess > process) { process = nowProcess; if (process
                 * % 10 == 0) System.out.println("下载进度:" + process); //
                 * 更新文件下载进度,值存放在process变量中 }
                 */

            }
            in.close();
            out.close();
            ftpClient.completePendingCommand();
        }
        return checkLocalFile;
    }

    /**
     * 断点续传
     * 
     * @param processStep
     *            需要显示的处理进度步进值
     * @param url
     *            地址
     * @param port
     *            端口
     * @param username
     *            用户名
     * @param password
     *            密码
     * @param remotePath
     *            远程路径
     * @param filename
     *            本地上传的文件名
     * @param file
     *            绝对路径
     * @return
     * @throws IOException
     */
    public static boolean uploadFileBreakPoint(String filename, File file) {
        boolean status = false;
        try {
            ftpConnect();
            // 转移目录到远端服务器目录
            ftpClient.changeWorkingDirectory(map.get("remotePath"));
            String f = new String(filename.getBytes(encoding), "iso-8859-1");
            // 检查ftp服务器中目录否已存在
            ResponseResult result = CreateDirecroty(map.get("remotePath"), f);
            // 文件存在,判断文件大小进行选择上传
            if (result.getStatus() == 200) {
                System.out.println("文件已存在");
                // 1.服务器文件大于将要上传文件,不需要上传,或者重新上传
                FTPFile[] listFiles = ftpClient.listFiles(map.get("remotePath")
                        + "/" + f);
                System.out.println(file.length());
                if (listFiles[0].getSize() >= file.length()) {
                    System.out.println("不需要上传");
                    return true;
                } else {
                    status = resumeBreakPoint(filename, file, listFiles);
                }
            }
            ftpClient.logout();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (ftpClient.isConnected()) {
                try {
                    ftpClient.disconnect();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return status;
    }

    /**
     * 上传文件
     * @param fileName
     * @param file
     * @return
     * @throws FileNotFoundException
     * @throws IOException
     * @throws UnsupportedEncodingException
     */
    public static boolean uploadFile(String fileName, File file)
            throws FileNotFoundException, IOException,
            UnsupportedEncodingException {
        boolean status = false;
        ftpConnect();
        ftpClient.changeWorkingDirectory(map.get("remotePath"));
//      String f = new String(fileName.getBytes(encoding), "iso-8859-1");
        BufferedInputStream inputStream = new BufferedInputStream(
                new FileInputStream(file));
        status = ftpClient.storeFile(new String(fileName.getBytes(encoding),
                "iso-8859-1"), inputStream);
        if (status) {
            System.out.println("上传成功!");
        }
        return status;
    }

    /**
     * 断点上传代码段
     * 
     * @param filename
     * @param file
     * @param listFiles
     * @return
     * @throws FileNotFoundException
     * @throws IOException
     * @throws UnsupportedEncodingException
     */
    private static boolean resumeBreakPoint(String filename, File file,
            FTPFile[] listFiles) throws FileNotFoundException, IOException,
            UnsupportedEncodingException {
        boolean status;
        // 2.服务器文件小于将要上传文件,进行断点续传
        // 显示进度的上传
        // long step = file.length() / 10;
        // long process = 0;
        long localreadbytes = 0L;
        RandomAccessFile raf = new RandomAccessFile(file, "rw");
        OutputStream out = ftpClient.appendFileStream(new String(filename
                .getBytes(encoding), "iso-8859-1"));
        // 断点续传
        ftpClient.setRestartOffset(listFiles[0].getSize());
        // process = listFiles[0].getSize() % step;
        raf.seek(listFiles[0].getSize());
        localreadbytes = listFiles[0].getSize();

        byte[] bytes = new byte[1024];
        int c;
        while ((c = raf.read(bytes)) != -1) {
            out.write(bytes, 0, c);
            localreadbytes += c;
            /*
             * if (localreadbytes / step != process) { process = localreadbytes
             * / step; System.out.println("上传进度:" + process); }
             */
        }
        out.flush();
        raf.close();
        out.close();
        boolean result = ftpClient.completePendingCommand();
        if (listFiles[0].getSize() > 0) {
            status = result ? true : false;
        } else {
            status = result ? true : false;
        }
        return status;
    }

    /**
     * ftp连接
     * @return
     * @throws SocketException
     * @throws IOException
     */
    private static boolean ftpConnect() throws SocketException, IOException {
        map = LoadProperties.GetAllProperties("ftp.properties");

        boolean status = false;
        ftpClient.connect(map.get("ftp_url"), Integer.valueOf(map.get("port")));// 连接FTP服务器
        // 登录
        ftpClient.login(map.get("username"), map.get("password"));

        // *************
        if (ftpClient.login(map.get("username"), map.get("password"))) {
            if (FTPReply.isPositiveCompletion(ftpClient.sendCommand(
                    "OPTS UTF8", "ON"))) {
                // 开启服务器对UTF-8的支持,如果服务器支持就用UTF-8编码,否则就使用本地编码(GBK).
                encoding = "UTF-8";
            } else {
                ftpClient.setControlEncoding(encoding);
            }
            System.out.println(encoding);
            ftpClient.enterLocalPassiveMode();
            ftpClient.setBufferSize(1024 * 1024 * 2);
            ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
            status = true;
        } else {
            ftpClient.disconnect();
            status = false;
            System.out.println("连接失败");
        }
        // *************
        return status;
    }

    /**
     * 在FTP服务器下载文件到本地
     */
    public void testDownFile() {
        try {
            boolean flag = downloadFile("7.txt",
                    "C:\\Users\\Administrator\\Desktop");
            System.out.println(flag);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 将本地文件上传到FTP服务器
     */
    public void testUpLoadFromDisk() {
        try {
            File file = new File(
                    "C:/Users/Public/Videos/Sample Videos/3 - 副本.mp4/");
            boolean flag;
//          flag = uploadFileBreakPoint("3 - 副本.mp4", file);
            flag = uploadFile("3 - 副本.mp4", file);
            System.out.println(flag);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) throws Exception {
//      FtpUtils fa = new FtpUtils();
////         fa.testDownFile();
//      fa.testUpLoadFromDisk();

    }
}

欢迎大家指正。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值