服务器直接文件传输

需求分析:今天有人提了这么一个问题,就是在两个服务器进行文件传递,在问过没有什么特殊需求之后提供如下demo。

文件传输1_FTP

如果在服务器是支持FTP传输的那就好办了,直接使用FTP进行文件传输就行,以下提供FTP工具类,在这里就不进行演示了,都是比较简单的东西,看下就明白了。

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

import org.apache.commons.net.PrintCommandListener;
import org.apache.commons.net.ftp.FTP;
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;

import lombok.extern.slf4j.Slf4j;

@Slf4j(topic="文件上传/下载===ftp服务器:")
public class FtpUtil {
    private static FTPClient mFTPClient = new FTPClient();
    private static FtpUtil ftp = new FtpUtil();
    
    public FtpUtil() {
        // 在控制台打印操作过程
         mFTPClient.addProtocolCommandListener(new PrintCommandListener(new PrintWriter(System.out)));
    }


    /**
     * 上传文件到ftp服务器
     */
    public static boolean ftpUpload(String fileName, String ftpUrl, int ftpPort,
            String ftpUsername, String ftpPassword, String ftpLocalDir, String ftpRemotePath) {
        boolean result = false;
        try {
            boolean isConnection = ftp.openConnection(ftpUrl, ftpPort, ftpUsername, ftpPassword);
            if (isConnection) {
                boolean isSuccess = ftp.upload(ftpRemotePath, ftpLocalDir + "/" + fileName);
                if (isSuccess) {
                    log.info("文件上传成功!");
                    result = true;
                } else {
                    log.info("文件上传失败!");
                    result = false;
                }
                ftp.logout();
            } else {
                log.info("链接ftp服务器失败,请检查配置信息是否正确!");
                result = false;
            }

        } catch (SocketException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 从ftp服务器下载文件到本地
     */
    public static boolean ftpDownload(String fileName, String ftpUrl, int ftpPort,
            String ftpUsername, String ftpPassword, String ftpRemotePath, String ftpDownDir) {
        boolean result = false;
        try {
            boolean isConnection = ftp.openConnection(ftpUrl, ftpPort, ftpUsername, ftpPassword);
            if (isConnection) {
                boolean isDownloadOk = ftp.downLoad(fileName, ftpDownDir);
                boolean isCreateOk = ftp.createDirectory(ftpRemotePath, ftp.mFTPClient);
                if (isDownloadOk && isCreateOk) {
                    log.info("文件下载成功!");
                    result = true;
                } else {
                    log.info("文件下载失败!");
                    result = false;
                }
                ftp.logout();
            } else {
                log.info("链接ftp服务器失败,请检查配置信息是否正确!");
                result = false;
            }

        } catch (SocketException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result;

    }

    /**
     * 连接ftp服务器
     * 
     * @param host
     *            ip地址
     * @param port
     *            端口号
     * @param account
     *            账号
     * @param pwd
     *            密码
     * @return 是否连接成功
     * @throws SocketException
     * @throws IOException
     */
    private boolean openConnection(String host, int port, String account, String pwd)
            throws SocketException, IOException {
        mFTPClient.setControlEncoding("UTF-8");
        mFTPClient.connect(host, port);

        if (FTPReply.isPositiveCompletion(mFTPClient.getReplyCode())) {
            mFTPClient.login(account, pwd);
            if (FTPReply.isPositiveCompletion(mFTPClient.getReplyCode())) {
                System.err.println(mFTPClient.getSystemType());
                FTPClientConfig config = new FTPClientConfig(mFTPClient.getSystemType().split(" ")[0]);
                config.setServerLanguageCode("zh");
                mFTPClient.configure(config);
                return true;
            }
        }
        disConnection();
        return false;
    }

    /**
     * 登出并断开连接
     */
    public void logout() {
        System.err.println("logout");
        if (mFTPClient.isConnected()) {
            System.err.println("logout");
            try {
                mFTPClient.logout();
                disConnection();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 断开连接
     */
    private void disConnection() {
        if (mFTPClient.isConnected()) {
            try {
                mFTPClient.disconnect();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 下载文件到本地地址
     * 
     * @param remotePath
     *            远程地址
     * @param loacal
     *            本地地址
     * @throws IOException
     */
    public boolean downLoad(String remotePath, String localDir) throws IOException {
        // 进入被动模式
        mFTPClient.enterLocalPassiveMode();
        // 以二进制进行传输数据
        mFTPClient.setFileType(FTP.BINARY_FILE_TYPE);
        FTPFile[] ftpFiles = mFTPClient.listFiles(remotePath);
        if (ftpFiles == null || ftpFiles.length == 0) {
            log.info("远程文件不存在");
            return false;
        } else if (ftpFiles.length > 1) {
            log.info("远程文件是文件夹");
            return false;
        }
        long lRemoteSize = ftpFiles[0].getSize();
        // 本地文件的地址
        File localFileDir = new File(localDir);
        if (!localFileDir.exists()) {
            localFileDir.mkdirs();
        }
        File localFile = new File(localFileDir, ftpFiles[0].getName());
        long localSize = 0;
        FileOutputStream fos = null;
        if (localFile.exists()) {
            if (localFile.length() == lRemoteSize) {
                System.err.println("已经下载完毕");
                return true;
            } else if (localFile.length() < lRemoteSize) {
                // 要下载的文件存在,进行断点续传
                localSize = localFile.length();
                mFTPClient.setRestartOffset(localSize);
                fos = new FileOutputStream(localFile, true);
            }
        }
        if (fos == null) {
            fos = new FileOutputStream(localFile);
        }
        InputStream is = mFTPClient.retrieveFileStream(remotePath);
        byte[] buffers = new byte[1024];
        long step = lRemoteSize / 10;
        long process = localSize / step;
        int len = -1;
        while ((len = is.read(buffers)) != -1) {
            fos.write(buffers, 0, len);
            localSize += len;
            long newProcess = localSize / step;
            if (newProcess > process) {
                process = newProcess;
                System.err.println("下载进度:" + process);
            }
        }
        is.close();
        fos.close();
        boolean isDo = mFTPClient.completePendingCommand();
        if (isDo) {
            System.err.println("下载成功");
        } else {
            System.err.println("下载失败");
        }
        return isDo;

    }

    /**
     * 创建远程目录
     * 
     * @param remote
     *            远程目录
     * @param ftpClient
     *            ftp客户端
     * @return 是否创建成功
     * @throws IOException
     */
    public boolean createDirectory(String remote, FTPClient ftpClient) throws IOException {
        String dirctory = remote.substring(0, remote.lastIndexOf("/") + 1);
        if (!dirctory.equalsIgnoreCase("/") && !ftpClient.changeWorkingDirectory(dirctory)) {
            int start = 0;
            int end = 0;
            if (dirctory.startsWith("/")) {
                start = 1;
            }
            end = dirctory.indexOf("/", start);
            while (true) {
                String subDirctory = remote.substring(start, end);
                if (!ftpClient.changeWorkingDirectory(subDirctory)) {
                    if (ftpClient.makeDirectory(subDirctory)) {
                        ftpClient.changeWorkingDirectory(subDirctory);
                    } else {
                        System.err.println("创建目录失败");
                        return false;
                    }
                }
                start = end + 1;
                end = dirctory.indexOf("/", start);
                if (end <= start) {
                    break;
                }
            }
        }
        return true;
    }

    /**
     * 上传的文件
     * 
     * @param remotePath
     *            上传文件的路径地址(文件夹地址)
     * @param localPath
     *            本地文件的地址
     * @throws IOException
     *             异常
     */
    public boolean upload(String remotePath, String localPath) throws IOException {
        // 进入被动模式
        mFTPClient.enterLocalPassiveMode();
        // 以二进制进行传输数据
        mFTPClient.setFileType(FTP.BINARY_FILE_TYPE);
        File localFile = new File(localPath);
        if (!localFile.exists()) {
            System.err.println("本地文件不存在");
            return false;
        }
        String fileName = localFile.getName();
        if (remotePath.contains("/")) {
            boolean isCreateOk = createDirectory(remotePath, mFTPClient);
            if (!isCreateOk) {
                System.err.println("文件夹创建失败");
                return false;
            }
        }

        // 列出ftp服务器上的文件
        FTPFile[] ftpFiles = mFTPClient.listFiles(remotePath);
        long remoteSize = 0l;
        String remoteFilePath = remotePath + "/" + fileName;
        if (ftpFiles.length > 0) {
            FTPFile mFtpFile = null;
            for (FTPFile ftpFile : ftpFiles) {
                if (ftpFile.getName().endsWith(fileName)) {
                    mFtpFile = ftpFile;
                    break;
                }
            }
            if (mFtpFile != null) {
                remoteSize = mFtpFile.getSize();
                if (remoteSize == localFile.length()) {
                    System.err.println("文件已经上传成功");
                    return true;
                }
                if (remoteSize > localFile.length()) {
                    if (!mFTPClient.deleteFile(remoteFilePath)) {
                        System.err.println("服务端文件操作失败");
                    } else {
                        boolean isUpload = uploadFile(remoteFilePath, localFile, 0);
                        System.err.println("是否上传成功:" + isUpload);
                    }
                    return true;
                }
                if (!uploadFile(remoteFilePath, localFile, remoteSize)) {
                    System.err.println("文件上传成功");
                    return true;
                } else {
                    // 断点续传失败删除文件,重新上传
                    if (!mFTPClient.deleteFile(remoteFilePath)) {
                        System.err.println("服务端文件操作失败");
                    } else {
                        boolean isUpload = uploadFile(remoteFilePath, localFile, 0);
                        System.err.println("是否上传成功:" + isUpload);
                    }
                    return true;
                }
            }
        }

        boolean isUpload = uploadFile(remoteFilePath, localFile, remoteSize);
        System.err.println("是否上传成功:" + isUpload);
        return isUpload;
    }

    /**
     * 上传文件
     * 
     * @param remoteFile
     *            包含文件名的地址
     * @param localFile
     *            本地文件
     * @param remoteSize
     *            服务端已经存在的文件大小
     * @return 是否上传成功
     * @throws IOException
     */
    private boolean uploadFile(String remoteFile, File localFile, long remoteSize) throws IOException {
        long step = localFile.length() / 10;
        long process = 0;
        long readByteSize = 0;
        RandomAccessFile randomAccessFile = new RandomAccessFile(localFile, "r");
        OutputStream os = mFTPClient.appendFileStream(remoteFile);
        if (remoteSize > 0) {
            // 已经上传一部分的时候就要进行断点续传
            process = remoteSize / step;
            readByteSize = remoteSize;
            randomAccessFile.seek(remoteSize);
            mFTPClient.setRestartOffset(remoteSize);
        }
        byte[] buffers = new byte[1024];
        int len = -1;
        while ((len = randomAccessFile.read(buffers)) != -1) {
            os.write(buffers, 0, len);
            readByteSize += len;
            long newProcess = readByteSize / step;
            if (newProcess > process) {
                process = newProcess;
                System.err.println("当前上传进度为:" + process);
            }
        }
        os.flush();
        randomAccessFile.close();
        os.close();
        boolean result = mFTPClient.completePendingCommand();
        return result;
    }

}
文件传输2_socket

在没有FTP的情况下呢,可以开启一个socket服务进行文件传输,提供以下demo。

import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.net.Socket;
 
/**
 * 文件传输Client端<br>
 * 功能说明:
 *
 * @version 1.0
 */
public class FileTransferClient extends Socket {
 
    private static final String SERVER_IP = "127.0.0.1"; // 服务端IP
    private static final int SERVER_PORT = 8899; // 服务端端口
 
    private Socket client;
 
    private FileInputStream fis;
 
    private DataOutputStream dos;
 
    /**
     * 构造函数<br/>
     * 与服务器建立连接
     * @throws Exception
     */
    public FileTransferClient() throws Exception {
        super(SERVER_IP, SERVER_PORT);
        this.client = this;
        System.out.println("Cliect[port:" + client.getLocalPort() + "] 成功连接服务端");
    }
 
    /**
     * 向服务端传输文件
     * @throws Exception
     */
    public void sendFile() throws Exception {
        try {
            File file = new File("D:\\tools\\jd-gui-windows-1.6.5.zip");
            if(file.exists()) {
                fis = new FileInputStream(file);
                dos = new DataOutputStream(client.getOutputStream());
 
                // 文件名和长度
                dos.writeUTF(file.getName());
                dos.flush();
                dos.writeLong(file.length());
                dos.flush();
 
                // 开始传输文件
                System.out.println("======== 开始传输文件 ========");
                byte[] bytes = new byte[1024];
                int length = 0;
                long progress = 0;
                while((length = fis.read(bytes, 0, bytes.length)) != -1) {
                    dos.write(bytes, 0, length);
                    dos.flush();
                    progress += length;
                    System.out.print("| " + (100*progress/file.length()) + "% |");
                }
                System.out.println();
                System.out.println("======== 文件传输成功 ========");
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if(fis != null)
                fis.close();
            if(dos != null)
                dos.close();
            client.close();
        }
    }
 
    /**
     * 入口
     * @param args
     */
    public static void main(String[] args) {
        try {
            FileTransferClient client = new FileTransferClient(); // 启动客户端连接
            client.sendFile(); // 传输文件
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
 
}
import java.io.DataInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.math.RoundingMode;
import java.net.ServerSocket;
import java.net.Socket;
import java.text.DecimalFormat;
 
/**
 * 文件传输Server端<br>
 * 功能说明:
 *
 * @author 大智若愚的小懂
 * @Date 2016年09月01日
 * @version 1.0
 */
public class FileTransferServer extends ServerSocket {
 
    private static final int SERVER_PORT = 8899; // 服务端端口
 
    private static DecimalFormat df = null;
 
    static {
        // 设置数字格式,保留一位有效小数
        df = new DecimalFormat("#0.0");
        df.setRoundingMode(RoundingMode.HALF_UP);
        df.setMinimumFractionDigits(1);
        df.setMaximumFractionDigits(1);
    }
 
    public FileTransferServer() throws Exception {
        super(SERVER_PORT);
    }
 
    /**
     * 使用线程处理每个客户端传输的文件
     * @throws Exception
     */
    public void load() throws Exception {
        while (true) {
            // server尝试接收其他Socket的连接请求,server的accept方法是阻塞式的
            Socket socket = this.accept();
            /**
             * 我们的服务端处理客户端的连接请求是同步进行的, 每次接收到来自客户端的连接请求后,
             * 都要先跟当前的客户端通信完之后才能再处理下一个连接请求。 这在并发比较多的情况下会严重影响程序的性能,
             * 为此,我们可以把它改为如下这种异步处理与客户端通信的方式
             */
            // 每接收到一个Socket就建立一个新的线程来处理它
            new Thread(new Task(socket)).start();
        }
    }
 
    /**
     * 处理客户端传输过来的文件线程类
     */
    class Task implements Runnable {
 
        private Socket socket;
 
        private DataInputStream dis;
 
        private FileOutputStream fos;
 
        public Task(Socket socket) {
            this.socket = socket;
        }
 
        @Override
        public void run() {
            try {
                dis = new DataInputStream(socket.getInputStream());
 
                // 文件名和长度
                String fileName = dis.readUTF();
                long fileLength = dis.readLong();
                File directory = new File("D:\\FTCache");
                if(!directory.exists()) {
                    directory.mkdir();
                }
                File file = new File(directory.getAbsolutePath() + File.separatorChar + fileName);
                fos = new FileOutputStream(file);
 
                // 开始接收文件
                byte[] bytes = new byte[1024];
                int length = 0;
                while((length = dis.read(bytes, 0, bytes.length)) != -1) {
                    fos.write(bytes, 0, length);
                    fos.flush();
                }
                System.out.println("======== 文件接收成功 [File Name:" + fileName + "] [Size:" + getFormatFileSize(fileLength) + "] ========");
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                try {
                    if(fos != null)
                        fos.close();
                    if(dis != null)
                        dis.close();
                    socket.close();
                } catch (Exception e) {}
            }
        }
    }
 
    /**
     * 格式化文件大小
     * @param length
     * @return
     */
    private String getFormatFileSize(long length) {
        double size = ((double) length) / (1 << 30);
        if(size >= 1) {
            return df.format(size) + "GB";
        }
        size = ((double) length) / (1 << 20);
        if(size >= 1) {
            return df.format(size) + "MB";
        }
        size = ((double) length) / (1 << 10);
        if(size >= 1) {
            return df.format(size) + "KB";
        }
        return length + "B";
    }
 
    /**
     * 入口
     * @param args
     */
    public static void main(String[] args) {
        try {
            FileTransferServer server = new FileTransferServer(); // 启动服务端
            server.load();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

今天就推荐着两种方案。


  转载请注明: RRYF 服务器直接文件传输

  目录