簡體   English   中英

通過FTP下載XML文件

[英]Downloading an XML file via FTP

我有一個數據庫中的源列表,用於從FTP服務器下載XML文件然后解析它。 scrpt捆綁到一個jar文件中,該文件每天使用Windows任務計划程序運行。 有時候請求會抓住某個xml文件。 到目前為止,它在2周內發生了大約3次,沒有我能看到的真實模式。

當它搞砸了,我去了它正在運行的計算機,我看到命令窗口打開並在xml完全下載之前停止。 如果我關閉命令窗口並手動運行任務,一切都會正常工作。

我用來下載xml文件的代碼是:

private void loadFTPFile(String host, String username, String password, String filename, String localFilename){
        System.out.println(localFilename);
        FTPClient client = new FTPClient();
        FileOutputStream fos = null;

        try {
            client.connect(host);
            client.login(username, password);
            String localFilenameOutput = createFile(assetsPath + localFilename);
            fos = new FileOutputStream(localFilenameOutput);
            client.retrieveFile(filename, fos);

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (fos != null) 
                    fos.close();
                client.disconnect();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

這個函數在循環中被調用,當它失敗時,一切都停止,腳本不會進入下一個feed。

我不確定發生了什么,可能連接丟失,但我認為如果發生這種情況,try / catch會捕獲。 我不確定是否會超時或需要使用線程(但我從未使用線程)

任何人都可以指出我正確的方向為什么會發生這種情況以及我可以做些什么來解決這個問題

UPDATE - 設置數據連接的超時

由於最后一個文件只是部分下載,並且給出了FTPClient.retrieveFile()的來源,我認為它可能是服務器端的問題(使它掛起,甚至死亡 - 誰知道 )。 顯然無法修復服務器甚至不知道發生了什么,無論如何我建議用setDataTimeout(int)添加超時並分別捕獲可能的SocketTimeoutException以記錄在不同的地方並可能發送到FTP服務器管理員(以及發生時的時間信息)這樣他們就可以合並日志並查看問題所在。

老答復

我沒有注意到您連接和登錄每一個文件,所以下面僅僅是一個優化不關閉控制連接,並成功地注銷,但它應該解決的問題。

您可以在調試模式下啟動JVM並在掛起時附加調試器,無論如何根據此答案此線程可能是網絡設備設備(路由器)上的超時問題。 來自FTPClient Javadoc

在文件傳輸期間,數據連接正忙,但控制連接處於空閑狀態。 FTP服務器知道控制連接正在使用中,因此不會因為缺乏活動而關閉它,但是網絡路由器要知道控制和數據連接是否相互關聯起來要困難得多。 某些路由器可能將控制連接視為空閑,如果通過數據連接的傳輸花費的時間超過路由器的允許空閑時間,則將其斷開。

對此的一個解決方案是在控制連接上發送安全命令(即NOOP)以重置路由器的空閑計時器。 這啟用如下:

ftpClient.setControlKeepAliveTimeout(300); // set timeout to 5 minutes

你檢查任何一個電話的返回狀態還是代碼?

有一個調用completePendingCommand()必須在occassion上使用。 這可能是需要研究的問題。

此外,您不會看到IO異常,我相信它會被重新打包為CopyStreamException

您可能還希望將返回值更改為布爾值,因為您捕獲了異常,至少調用循環將知道轉移是否發生。

private boolean loadFTPFile(String host, String username, String password, String filename, String localFilename){
    System.out.println(localFilename);
    FTPClient client = new FTPClient();
    FileOutputStream fos = null;

    try {
        client.connect(host);

        int reply = client.getReplyCode();

        if (!FTPReply.isPositiveCompletion(reply)){
            client.disconnect();
            System.err.println("FTP server refused connection.");
            return false;
        }


        if (!client.login(username, password)){
            client.logout();
            return false;
        }

        String localFilenameOutput = createFile(assetsPath + localFilename);
        fos = new FileOutputStream(localFilenameOutput);
        boolean result = client.retrieveFile(filename, fos);

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");

        if (result){
            System.out.println("\tFile Transfer Completed Successfully at: " + sdf.format(Calendar.getInstance().getTime()));

            // ftp.completePendingCommand();
        }
        else {
            System.out.println("\tFile Transfer Failed at: " + sdf.format(Calendar.getInstance().getTime()));
        }

    return result;
    }catch (CopyStreamException cse){
        System.err.println("\n\tFile Transfer Failed at: " + sdf.format(Calendar.getInstance().getTime()));
        System.err.println("Error Occurred Retrieving File from Remote System, aborting...\n");
        cse.printStackTrace(System.err);
        System.err.println("\n\nIOException Stack Trace that Caused the Error:\n");
        cse.getIOException().printStackTrace(System.err);
        return false;
    }catch (Exception e){
        System.err.println("\tFile Transfer Failed at: " + sdf.format(Calendar.getInstance().getTime()));
        System.out.println("Error Occurred Retrieving File from Remote System, aborting...");
        e.printStackTrace(System.err);
        return false;
    } finally {
        try {
            if (fos != null) 
                fos.close();
            client.disconnect();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

這不是一個線程問題。 它可能是由循環中的某些東西引起的,因為該代碼看起來應該清理得很好。 也就是說,對於測試,您可能想要添加

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

IOException catch子句之后。 可能會拋出另一個異常。

另外,如果您一次從數據庫結果集中提取結果並進行FTP獲取,那可能是個問題。 除非結果全部由JDBC調用立即帶回,否則也可能超時。 並非所有數據庫查詢實際上都會立即將整個結果集返回給客戶端。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM