简体   繁体   English

使用apache FTPClient从FTP服务器下载文件

[英]File Download from a FTP Server using apache FTPClient

I am using apache's FTPClient to download files from a FTP server. 我正在使用apache的FTPClient从FTP服务器下载文件。 My scenario is - the FTP server can loose network connectivity and may remain disconnected for a max of 1 day. 我的情况是-FTP服务器可能会失去网络连接,并且可能最多保持1天处于断开连接状态。 When it connects back, download of the files should start from where it was left. 重新连接后,应从剩余位置开始下载文件。 I am using the following code to connect to the server and then download the file from the server 我正在使用以下代码连接到服务器,然后从服务器下载文件

public void retrieve(String server, int port, String username,
        String password, String remote, String local, int fileType,
        ProgressHandler progressHandler) throws Exception {     
    final FTPClient ftp = new FTPClient();
    Date date = new Date();
    long startTime_ms = date.getTime();
    if (progressHandler != null) {
        ftp.setCopyStreamListener(new FtpCopyStreamListener(progressHandler));
    }

    ftpConnect(server,ftp, port,startTime_ms);


    if(ftp.getReplyCode()==0 || !String.valueOf(ftp.getReplyCode()).startsWith("2")){
        cleanup(ftp, "Could not log into server: " + server, null);
        return;
    }

    boolean loggedIn = false;
    try {
        if (username == null || username.isEmpty()) {
            username = "anonymous";
            password = System.getProperty("user.name") + "@"
                    + InetAddress.getLocalHost().getHostName();
        }
        if (!ftp.login(username, password)) {
            ftp.logout();
            cleanup(ftp, "Could not log into server: " + server, null);
        }
        loggedIn = true;

        ftp.setFileType(fileType);
        ftp.enterLocalPassiveMode();
        OutputStream output = null;
        try {
            output = new FileOutputStream(local);
            LOGGER.info("About to download " + remote + " from " + server
                    + " on " + (port > 0 ? port : ftp.getDefaultPort())
                    + " to " + local);              
            ftp.setControlKeepAliveTimeout(300);
            boolean isFileDownloaded = false;
            try{
                isFileDownloaded = ftp.retrieveFile(remote, output);

            }
            catch(IOException ex){
                if(ftp.isConnected()){

                    try{
                        int retryCode = 0;
                        while (!String.valueOf(retryCode).startsWith("2") && (new Date().getTime() < (startTime_ms + TOTAL_DURATION_MSECS))){
                            try{

                                 retryCode = ftp.retr(local);
                            }catch(Exception e1){
                                Thread.sleep(1000);
                                System.out.println("File not downloaded !! " + e1.toString());
                                ftpConnect(server, ftp, port, startTime_ms);
                            }

                        }
                    }catch(Exception e){
                        //ftp.getReplyCode()
                        //throw e;
                        //disconnect(ftp);
                        //ftpConnect(server, ftp, port, startTime_ms);

                        System.out.println("File not downloaded !! " + e.toString());
                    }                   
                }
            }
            if(isFileDownloaded){
                LOGGER.info("Finished downloading " + remote + " from "
                        + server + " on "
                        + (port > 0 ? port : ftp.getDefaultPort()) + " to "
                        + local);
            }
            else{
                System.out.println("File not downloaded !! ");
            }           

        }catch(IOException io){
            io.printStackTrace();

            throw io;
        }           
        finally {
            if (output != null) {
                try {
                    output.close();
                } catch (IOException f) {
                    LOGGER.severe("output.close() error: "
                            + ServiceUtils.stackToString(f));
                }
            }
        }
    }       
    catch (FTPConnectionClosedException e) {
        LOGGER.severe("Server closed connection: " + server + " "
                + ServiceUtils.stackToString(e));
        throw e;
    } catch (IOException e) {
        LOGGER.severe("IOException, server: " + server + " "
                + ServiceUtils.stackToString(e));
        throw e;
    } finally {
        if (loggedIn) {
            try {
                ftp.logout();
            } catch (IOException f) {
                LOGGER.severe("ftp.logout() error: "
                        + ServiceUtils.stackToString(f));
            }
        }
        disconnect(ftp);
    }
}

My question is basically if the retrieveFile() method fails is there any anyway I can reconnect and start downloading from the point it was disconnected. 我的问题基本上是,retrieveFile()方法是否失败,无论如何我都可以重新连接并从断开连接的地方开始下载。

right now I am using a Microsoft IIS server as my FTP server but in the production environment it will be a FileZilla FTP server. 现在,我使用Microsoft IIS服务器作为FTP服务器,但是在生产环境中,它将是FileZilla FTP服务器。

Any help is appreciated. 任何帮助表示赞赏。 Thanks 谢谢

Sorry for very late response. 抱歉,回复太晚了。 Here what I did to solve the problem: 这是我为解决问题所做的工作:

  1. Setup a FileZilla server 设置FileZilla服务器
  2. Use retrieveFileStream instead of retrieveFile. 使用retrieveFileStream而不是retrieveFile。
  3. Keep a count of bytes written and use the same output stream to write. 保持写入的字节数,并使用相同的输出流进行写入。

      BufferedInputStream inputStream = null; BufferedOutputStream outputStream = null; InputStream in = null; int osCount = 0; in = ftp.retrieveFileStream(remote); inputStream = new BufferedInputStream(in); File localFile = new File(local, fileName); outputStream = new BufferedOutputStream(new FileOutputStream(localFile)); for (int read = inputStream.read(); read != -1; read = inputStream.read()) { outputStream.write(read); osCount++; } outputStream.flush(); if (osCount < fileSize) { System.out.println(fileName + ": Errored out !!!"); BufferedInputStream inputStream1 = null; InputStream in1 = null; if (ftp.isConnected()) { try { while (osCount < fileSize && new Date().getTime() < (startTime_ms + TOTAL_DURATION_MSECS)) { try { disconnect(ftp); ftpConnect(server, ftp, port, startTime_ms); ftp.login(username, password); ftp.setRestartOffset(osCount); System.out.println(fileName + ": Re reading from position " + osCount); in1 = ftp.retrieveFileStream(remote); inputStream1 = new BufferedInputStream(in1); for (int read = inputStream1.read(); read != -1; read = inputStream1.read()) { outputStream.write(read); osCount++; } outputStream.flush(); if(FTPReply.isPositiveCompletion(ftp.getReplyCode())){ isErrored = true; break; } } catch (Exception e1) { Thread.sleep(1000); LOGGER.severe(fileName + ": File not downloaded " + server + " " + ServiceUtils.stackToString(e1)); } } } catch (Exception e) { LOGGER.severe(fileName + ": File not downloaded " + server + " " + ServiceUtils.stackToString(e)); } } } 

FTPCLient.restart(...) is protected . FTPCLient.restart(...) protected I think setRestartOffset(...) and retrieveFile(...) is the way to go: "Note: if you have used setRestartOffset(long), the file data will start from the selected offset." 我认为setRestartOffset(...)retrieveFile(...)setRestartOffset(...)的方法: “注意:如果您使用过setRestartOffset(long),则文件数据将从选定的偏移量开始。” .

I'd also catch CopyStreamException instead of just IOException : "The CopyStreamException allows you to determine the number of bytes transferred" '. 我还会捕获CopyStreamException而不是仅捕获IOException“ CopyStreamException允许您确定传输的字节数 ”。

You check for ftp.isConnected() before entering the retry block but you write "FTP server loose network connectivity and may remain disconnected" . 在进入重试块之前,请检查ftp.isConnected() ,但是您写了“ FTP服务器网络连接松动,并且可能保持断开连接” I guess that if you enter this catch block connectivity has been lost already, which is one of the reasons for entering this block at all. 我猜想,如果您输入此catch块,则连接性已经丢失,这就是根本无法进入此块的原因之一。

What is ftp.retr(...) doing? ftp.retr(...)在做什么? Retrying, yes, but does it work as intended? 重试,是的,但是它能按预期工作吗?

What do you get if you debug your code by: 如果通过以下方式调试代码,会得到什么?

  • setting a breakpoint at ftp.isConnected() ftp.isConnected()处设置断点
  • retrieving a file that is large enough to take a while to download 检索足够大的文件以花费一段时间下载
  • pulling out your network cable while the transfer is in progress 进行传输时拔出网络电缆
  • looking at the value of ftp.isConnected() 查看ftp.isConnected()的值
  • if it is true (unlikely, but who knows) what does ftp.retr(...) return? 如果它是true (不太可能,但是谁知道) ftp.retr(...)返回什么?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM