通过FTP下载XML文件

时间:2012-08-22 17:57:43

标签: java ftp windows-scheduler

我有一个数据库中的供稿列表,用于从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会捕获。我不确定是否会超时或者需要使用线程(但我从未使用线程)

有没有人能指出我正确的方向为什么会发生这种情况以及我可以做些什么来解决这个问题

3 个答案:

答案 0 :(得分:2)

UPDATE - 设置数据连接的超时

由于最后一个文件只是部分下载,并且给出了FTPClient.retrieveFile()的来源,我认为它可能是服务器端的问题(使它挂起,甚至死亡的东西 - 谁知道)。显然,人们无法修复服务器甚至无法知道发生了什么,无论如何我建议用setDataTimeout(int)添加超时并分别捕获可能的SocketTimeoutException以便在不同的地方登录并可能发送到FTP服务器管理员(以及发生时的时间信息),以便他们可以合并日志并查看问题所在。

OLD ANSWER

我没有注意到您为每个文件连接并登录,因此以下只是优化不关闭控件连接并成功注销,但它应该 not not 解决问题。

您可以在调试模式下启动JVM并在挂起时附加调试器,无论如何根据this answerthis thread它可能是网络设备设备(路由器)上的超时问题。来自FTPClient Javadoc

  

在文件传输期间,数据连接正忙,但控件   连接空闲。 FTP服务器知道控制连接在   使用,所以不会因为缺乏活动而关闭它,但这要困难得多   让网络路由器知道控制和数据连接   相互关联。一些路由器可能会对待控件   连接为空闲,如果通过数据传输则断开连接   连接所需的时间超过路由器允许的空闲时间。

对此的一个解决方案是通过控制连接发送安全命令(即NOOP)以重置路由器的空闲计时器。这启用如下:

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

答案 1 :(得分:1)

你检查任何一个电话的返回状态还是代码?

有一个必须在场合使用的调用completePendingCommand()。这可能是需要研究的问题。

此外,您不会看到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();
        }
    }
}

答案 2 :(得分:0)

这不是一个线程问题。它可能是由循环中的某些东西引起的,因为该代码看起来应该清理得很好。也就是说,为了进行测试,您可能需要添加

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

IOException catch子句之后。可能会抛出另一个异常。

另一件事,如果您一次从数据库结果集中提取结果并进行FTP获取,那可能是个问题。除非结果全部由JDBC调用立即带回,否则也可能超时。并非所有数据库查询实际上都会立即将整个结果集返回给客户端。