1

这是一个工作问题,我已经努力解决了大约一个星期,但没有成功。

我有使用 apache commons net FTPClient 库将文件发送到大型机的遗留 Java 代码。该代码适用于 86Mb 以下的文件。但是,当遇到超过 86Mb 的文件时,它会失败并返回 CopyStreamException(没有其他有用信息)。我添加了超时和 CopyStreamListener 无济于事。侦听器输出一些消息,表明 ftp 正在成功地将数据缓冲区上传到大型机,直到达到 86Mb(示例日志输出包含在下面)。

我最初认为问题与网络/防火墙有关(这就是为什么您会在代码中看到如此多的超时操作),但现在我明白这与我发送到大型机的空间分配命令有关。我在这里得到了一位大型机专家的帮助,他就 BLKSIZE、SPACE、LRECL 等的不同组合提出了许多建议。但没有一个奏效。有一次我确实完成了传输工作,但是大型机工作人员随后告诉我,在大型机上创建的文件的块大小和格式参数不正确,所以我不得不放弃它(我会解释它是什么在下面的这种情况下工作)。

首先,这是Java代码:

public static boolean copyFileThruFTP(
    String srcFileName, String remoteFileName, Properties exportProps) {
    boolean success = true;
    String serverUserName = exportProps.getProperty(WebUtil.FTP_SERVER_USER);
    String serverPwd = exportProps.getProperty(WebUtil.FTP_SERVER_PWD);
    String serverIp = exportProps.getProperty(WebUtil.FTP_SERVER_IP);
    File f = new File(srcFileName);
    FTPClient ftpClient = null;
    try {
        String errorMessage = null;
        FileInputStream input = new FileInputStream(f);
        ftpClient = new FTPClient();

        ftpClient.setDataTimeout(6000000); // 100 minutes
        ftpClient.setConnectTimeout(6000000); // 100 minutes
        ftpClient.connect(serverIp);
        int reply = ftpClient.getReplyCode();

        if (!FTPReply.isPositiveCompletion(reply)) {
            errorMessage = "FTP server refused connection: " + ftpClient.getReplyString();
        } else {
            if (!ftpClient.login(serverUserName,serverPwd)) {
                errorMessage = "Failed to copy file thru FTP: login failed.";
            } else {
                ftpClient.setBufferSize(1024000);
                ftpClient.setControlKeepAliveTimeout(30); // sends a keepalive every thirty seconds

                if (ftpClient.deleteFile(remoteFileName)) {
                    log.warn("Deleted existing file from remote server: " + remoteFileName);
                }
                ftpClient.setFileTransferMode(FTP.ASCII_FILE_TYPE);
                ftpClient.setFileType(FTP.ASCII_FILE_TYPE);
                ftpClient.sendSiteCommand("RECFM=FB");
                ftpClient.sendSiteCommand("LRECL=2000");
                ftpClient.sendSiteCommand("BLKSIZE=27000");
                //ftpClient.sendSiteCommand("DCB=(RECFM=FB,LRECL=2000,BLKSIZE=26000)");
                ftpClient.sendSiteCommand("SPACE=(TRK,(500,500),RLSE)");

                OutputStream ftpOut = ftpClient.storeFileStream(remoteFileName);
                if (ftpOut == null) {
                    errorMessage = "FTP server could not open file for write: " + ftpClient.getReplyString();
                } else {
                    OutputStream output = new BufferedOutputStream(ftpOut);

                    log.warn("copyFileThruFTP calling copyStream() for file: " + f.getAbsolutePath());
                    Util.copyStream(input, output, ftpClient.getBufferSize(), f.length(),
                        new CopyStreamAdapter() {
                            public void bytesTransferred(
                                long totalBytesTransferred, int bytesTransferred, long streamSize) {
                                    log.warn(bytesTransferred + " bytes written; total: " + totalBytesTransferred + " of " + streamSize);
                            }
                        });
                    input.close();
                    output.close();
                    if (!ftpClient.completePendingCommand()) {
                        errorMessage = "Failed to copy file thru FTP: completePendingCommand failed.";
                    }
                }
            }
            ftpClient.logout();
            ftpClient.disconnect();
            ftpClient = null;
        }
        if (!StringUtils.isEmpty(errorMessage)) {
            log.error(errorMessage);
            System.out.print(errorMessage);
            success = false;
        }
    } catch (CopyStreamException cse){
        cse.printStackTrace();
        log.error("Failed to copy file thru FTP (CopyStreamException).", cse);
        success = false;
    } catch (IOException e){
        e.printStackTrace();
        log.error("Failed to copy file thru FTP (IOException).", e);
        success = false;
    } finally {
        try {
            if (ftpClient != null) {
                ftpClient.logout();
                ftpClient.disconnect();
            }
        } catch (IOException ignore) {}
    }

    return success;    
}

现在,正如我所说,这段代码对 86Mb 以下的所有文件都非常有效,所以虽然从知识的角度来看它可能很有用,但我并不需要 Java 编码风格等方面的提示。另外请注意,在发布此方法时,我删除了注释和无关代码,因此可能存在一两个语法错误,尽管当我将其复制回 eclipse 时没有看到任何错误。我要解决的是为什么此代码适用于小文件,但不适用于大文件!

以下是大文件的日志输出示例(为美观而稍作修改):


2012-02-29 11:13 WARN - copyFileThruFTP calling copyStream() for file: C:\data\mergedcdi\T0090200.txt
2012-02-29 11:13 WARN - 1024000 bytes; total: 1024000 of 96580484
2012-02-29 11:13 WARN - 1024000 bytes; total: 2048000 of 96580484
2012-02-29 11:13 WARN - 1024000 bytes; total: 3072000 of 96580484
2012-02-29 11:13 WARN - 1024000 bytes; total: 4096000 of 96580484
2012-02-29 11:13 WARN - 1024000 bytes; total: 5120000 of 96580484
2012-02-29 11:13 WARN - 1024000 bytes; total: 6144000 of 96580484
2012-02-29 11:13 WARN - 1024000 bytes; total: 7168000 of 96580484
2012-02-29 11:13 WARN - 1024000 bytes; total: 8192000 of 96580484
2012-02-29 11:13 WARN - 1024000 bytes; total: 9216000 of 96580484
2012-02-29 11:13 WARN - 1024000 bytes; total: 10240000 of 96580484
2012-02-29 11:13 WARN - 1024000 bytes; total: 11264000 of 96580484
2012-02-29 11:13 WARN - 1024000 bytes; total: 12288000 of 96580484
2012-02-29 11:13 WARN - 1024000 bytes; total: 13312000 of 96580484
2012-02-29 11:14 WARN - 1024000 bytes; total: 14336000 of 96580484
2012-02-29 11:14 WARN - 1024000 bytes; total: 15360000 of 96580484
2012-02-29 11:14 WARN - 1024000 bytes; total: 16384000 of 96580484
2012-02-29 11:14 WARN - 1024000 bytes; total: 17408000 of 96580484
2012-02-29 11:14 WARN - 1024000 bytes; total: 18432000 of 96580484
2012-02-29 11:14 WARN - 1024000 bytes; total: 19456000 of 96580484
2012-02-29 11:14 WARN - 1024000 bytes; total: 20480000 of 96580484
2012-02-29 11:14 WARN - 1024000 bytes; total: 21504000 of 96580484
2012-02-29 11:14 WARN - 1024000 bytes; total: 22528000 of 96580484
2012-02-29 11:14 WARN - 1024000 bytes; total: 23552000 of 96580484
2012-02-29 11:14 WARN - 1024000 bytes; total: 24576000 of 96580484
2012-02-29 11:14 WARN - 1024000 bytes; total: 25600000 of 96580484
2012-02-29 11:14 WARN - 1024000 bytes; total: 26624000 of 96580484
2012-02-29 11:14 WARN - 1024000 bytes; total: 27648000 of 96580484
2012-02-29 11:14 WARN - 1024000 bytes; total: 28672000 of 96580484
2012-02-29 11:14 WARN - 1024000 bytes; total: 29696000 of 96580484
2012-02-29 11:14 WARN - 1024000 bytes; total: 30720000 of 96580484
2012-02-29 11:14 WARN - 1024000 bytes; total: 31744000 of 96580484
2012-02-29 11:14 WARN - 1024000 bytes; total: 32768000 of 96580484
2012-02-29 11:14 WARN - 1024000 bytes; total: 33792000 of 96580484
2012-02-29 11:14 WARN - 1024000 bytes; total: 34816000 of 96580484
2012-02-29 11:15 WARN - 1024000 bytes; total: 35840000 of 96580484
2012-02-29 11:15 WARN - 1024000 bytes; total: 36864000 of 96580484
2012-02-29 11:15 WARN - 1024000 bytes; total: 37888000 of 96580484
2012-02-29 11:15 WARN - 1024000 bytes; total: 38912000 of 96580484
2012-02-29 11:15 WARN - 1024000 bytes; total: 39936000 of 96580484
2012-02-29 11:15 WARN - 1024000 bytes; total: 40960000 of 96580484
2012-02-29 11:15 WARN - 1024000 bytes; total: 41984000 of 96580484
2012-02-29 11:15 WARN - 1024000 bytes; total: 43008000 of 96580484
2012-02-29 11:15 WARN - 1024000 bytes; total: 44032000 of 96580484
2012-02-29 11:15 WARN - 1024000 bytes; total: 45056000 of 96580484
2012-02-29 11:15 WARN - 1024000 bytes; total: 46080000 of 96580484
2012-02-29 11:15 WARN - 1024000 bytes; total: 47104000 of 96580484
2012-02-29 11:15 WARN - 1024000 bytes; total: 48128000 of 96580484
2012-02-29 11:15 WARN - 1024000 bytes; total: 49152000 of 96580484
2012-02-29 11:15 WARN - 1024000 bytes; total: 50176000 of 96580484
2012-02-29 11:15 WARN - 1024000 bytes; total: 51200000 of 96580484
2012-02-29 11:15 WARN - 1024000 bytes; total: 52224000 of 96580484
2012-02-29 11:15 WARN - 1024000 bytes; total: 53248000 of 96580484
2012-02-29 11:16 WARN - 1024000 bytes; total: 54272000 of 96580484
2012-02-29 11:16 WARN - 1024000 bytes; total: 55296000 of 96580484
2012-02-29 11:16 WARN - 1024000 bytes; total: 56320000 of 96580484
2012-02-29 11:16 WARN - 1024000 bytes; total: 57344000 of 96580484
2012-02-29 11:16 WARN - 1024000 bytes; total: 58368000 of 96580484
2012-02-29 11:16 WARN - 1024000 bytes; total: 59392000 of 96580484
2012-02-29 11:16 WARN - 1024000 bytes; total: 60416000 of 96580484
2012-02-29 11:16 WARN - 1024000 bytes; total: 61440000 of 96580484
2012-02-29 11:16 WARN - 1024000 bytes; total: 62464000 of 96580484
2012-02-29 11:16 WARN - 1024000 bytes; total: 63488000 of 96580484
2012-02-29 11:16 WARN - 1024000 bytes; total: 64512000 of 96580484
2012-02-29 11:16 WARN - 1024000 bytes; total: 65536000 of 96580484
2012-02-29 11:16 WARN - 1024000 bytes; total: 66560000 of 96580484
2012-02-29 11:16 WARN - 1024000 bytes; total: 67584000 of 96580484
2012-02-29 11:16 WARN - 1024000 bytes; total: 68608000 of 96580484
2012-02-29 11:16 WARN - 1024000 bytes; total: 69632000 of 96580484
2012-02-29 11:16 WARN - 1024000 bytes; total: 70656000 of 96580484
2012-02-29 11:16 WARN - 1024000 bytes; total: 71680000 of 96580484
2012-02-29 11:16 WARN - 1024000 bytes; total: 72704000 of 96580484
2012-02-29 11:16 WARN - 1024000 bytes; total: 73728000 of 96580484
2012-02-29 11:17 WARN - 1024000 bytes; total: 74752000 of 96580484
2012-02-29 11:17 WARN - 1024000 bytes; total: 75776000 of 96580484
2012-02-29 11:17 WARN - 1024000 bytes; total: 76800000 of 96580484
2012-02-29 11:17 WARN - 1024000 bytes; total: 77824000 of 96580484
2012-02-29 11:17 WARN - 1024000 bytes; total: 78848000 of 96580484
2012-02-29 11:17 WARN - 1024000 bytes; total: 79872000 of 96580484
2012-02-29 11:17 WARN - 1024000 bytes; total: 80896000 of 96580484
2012-02-29 11:17 WARN - 1024000 bytes; total: 81920000 of 96580484
2012-02-29 11:17 WARN - 1024000 bytes; total: 82944000 of 96580484
2012-02-29 11:17 WARN - 1024000 bytes; total: 83968000 of 96580484
2012-02-29 11:17 WARN - 1024000 bytes; total: 84992000 of 96580484
2012-02-29 11:17 WARN - 1024000 bytes; total: 86016000 of 96580484
2012-02-29 11:17 ERROR- Failed to copy file thru FTP (CopyStreamException).
org.apache.commons.net.io.CopyStreamException: IOException caught while copying.
    at org.apache.commons.net.io.Util.copyStream(Util.java:130)
    at org.apache.commons.net.io.Util.copyStream(Util.java:174)
    at com.pa.rollupedit.util.WebUtil.copyFileThruFTP(WebUtil.java:1120)
    at com.pa.rollupedit.util.CdiBuilder.process(CdiBuilder.java:361)
    at com.pa.rollupedit.controller.ExportCDI.doGet(ExportCDI.java:55)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:707)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:820)
    at weblogic.servlet.internal.StubSecurityHelper$ServletServiceAction.run(StubSecurityHelper.java:227)
    at weblogic.servlet.internal.StubSecurityHelper.invokeServlet(StubSecurityHelper.java:125)
    at weblogic.servlet.internal.ServletStubImpl.execute(ServletStubImpl.java:292)
    at weblogic.servlet.internal.TailFilter.doFilter(TailFilter.java:26)
    at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:42)
    at com.pa.rollupedit.controller.LoginFilter.doFilter(LoginFilter.java:90)
    at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:42)
    at com.pa.rollupedit.util.RequestTimeFilter.doFilter(RequestTimeFilter.java:18)
    at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:42)
    at weblogic.servlet.internal.WebAppServletContext$ServletInvocationAction.run(WebAppServletContext.java:3496)
    at weblogic.security.acl.internal.AuthenticatedSubject.doAs(AuthenticatedSubject.java:321)
    at weblogic.security.service.SecurityManager.runAs(Unknown Source)
    at weblogic.servlet.internal.WebAppServletContext.securedExecute(WebAppServletContext.java:2180)
    at weblogic.servlet.internal.WebAppServletContext.execute(WebAppServletContext.java:2086)
    at weblogic.servlet.internal.ServletRequestImpl.run(ServletRequestImpl.java:1406)
    at weblogic.work.ExecuteThread.execute(ExecuteThread.java:201)
    at weblogic.work.ExecuteThread.run(ExecuteThread.java:173)


好的,现在来看看大型机上发生的事情。以下是大型机人提供给我的关于传输不完整生成的文件的信息:

    Data Set Name . . . . : BSFP.ICEDCDI.SPC10.T0090200

General Data Current Allocation Management class . . : MCDFLT Allocated tracks . : 1,650 Storage class . . . : SCSTD Allocated extents . : 32 Volume serial . . . : SMS217 + Device type . . . . : 3390 Data class . . . . . : DCDFLT Organization . . . : PS Current Utilization Record format . . . : FB Used tracks . . . . : 1,650 Record length . . . : 2000 Used extents . . . : 32 Block size . . . . : 26000 1st extent tracks . : 100 Secondary tracks . : 50 Dates Data set name type : Creation date . . . : 2012/02/29 SMS Compressible. . : NO Referenced date . . : 2012/02/29 Expiration date . . : None

请注意,记录长度、记录格式和块大小似乎与您期望的一样,它们基于我发送的站点命令。但是,在我看来,第一个范围和次要轨道是不正确的。大型机专家给了我大约 10 种不同的 SPACE 命令来尝试(以及对块大小的一些修改)。记录大小绝对是 2000 个字符,因此保持一致。但到目前为止,他的任何建议都没有奏效。

就我自己而言,我发现了另一种设置参数的方法,并曾尝试过。您可以在代码中将其视为注释掉的行:

 //ftpClient.sendSiteCommand("DCB=(RECFM=FB,LRECL=2000,BLKSIZE=26000)");

有趣的是,当我使用这个命令(并注释掉RECFM/LRECL/BLKSIZE命令)时,ftp传输成功了!!但是主机大佬随后分享了如下远程文件信息,说明各种参数设置不正确。DCB 命令似乎根本不起作用。


    Data Set Name . . . . : BSFP.ICEDCDI.SPC10.T0090200

General Data Current Allocation Management class . . : MCDFLT Allocated tracks . : 230 Storage class . . . : SCSTD Allocated extents . : 4 Volume serial . . . : SMS195 Device type . . . . : 3390 Data class . . . . . : DCDFLT Organization . . . : PS Current Utilization Record format . . . : VB Used tracks . . . . : 230 Record length . . . : 256 Used extents . . . : 4 Block size . . . . : 27000 1st extent tracks . : 100 Secondary tracks . : 50 Dates Data set name type : Creation date . . . : 2012/02/28 SMS Compressible. . : NO Referenced date . . : 2012/02/29 Expiration date . . : None

不用说,这确实对事情产生了影响。

今天早上的更新:大型机专家联系了其他大型机专家,其中一位告诉他“TRK”在 SPACE 命令中不正确,而是使用以下命令:


    ftpClient.sendSiteCommand("SPACE=(TRA,(PRI=500,SEC=500))");

我尝试了这个(以及其他变体,例如没有 PRI= 和 SEC=),但结果完全相同(即在 86Mb 时失败)。

如您所见,这不是一个轻浮的问题。我什至没有深入研究我在验证这不是网络问题时所经历的许多变化。在这一点上,我大约 98.6% 确定这个问题是由大型机站点命令引起的。

如果您能提供任何帮助,我将不胜感激!!

4

2 回答 2

4

由于您在一定规模上失败了,因此这是您的大型机空间命令。

一个大型机文件只能有 16 个扩展区、1 个主分配和 15 个辅助分配。如果磁盘包已满或几乎已满,您可能无法获得主分配。

在您当前的分配中,您要求 500 个主要轨道和 15 * 500 个辅助轨道,总共 8,000 个轨道。一个磁道将容纳 2 或 3 个 26,000 字节的块,具体取决于磁盘驱动器磁道的大小。如果您指定块大小为 0,IBM 操作系统将计算最有效的块大小。

一点数学表明您已经分配了 208,000 条记录(最坏情况)。

您可能应该在圆柱体中指定您的空间,并有一个小的主要和较大的次要。就像是:

ftpClient.sendSiteCommand("SPACE=(CYL,(30,300),RLSE)"); 

如果您的大型机商店坚持要您指定轨道,请尝试以下操作:

ftpClient.sendSiteCommand("SPACE=(TRK,(450,4500),RLSE)");

我让这两个数字都可以被 15 整除,因为如果我没记错的话,一个圆柱体包含 15 个磁道。

编辑添加:

我刚刚在IBM 网站上找到了IBM FTP 命令页面。看来您必须单独发送空格命令的每个部分,就像 DCB 命令一样。

ftpClient.sendSiteCommand("TR");
ftpClient.sendSiteCommand("PRI=450");
ftpClient.sendSiteCommand("SEC=4500");
于 2012-02-29T18:29:21.000 回答
4

我想对 Gilbert Le Blanc 给出的出色回答添加一些评论

指定一个小的主要空间和大的辅助空间的原因有点违反直觉。主空间分配总是要求连续的空间(即一大块)。当找不到具有该数量的连续空间的卷(磁盘)时,该作业将失败并返回 B37 代码。在主空间分配占卷的很大比例的情况下(3390 DASD 设备实际上相当小 - 大约 10Gb 左右),找不到具有所需空间的卷的可能性可能很大。因此,这项工作在 B37 上爆发了。

次要分配不必分配连续的块,并且可以跨越多个卷。通过请求相当小的主要数量,您可以通过允许数据集分配辅助空间来满足总空间要求来避免 B37 异常终止。这种方法的问题是每个卷只能获得 15 个辅助扩展区(这是一个人为但历史性的限制,可以通过您商店中的 DASD 管理来解除)。为避免超出范围限制,导致 E37 异常终止,您请求较大的范围大小。

最后,您可以指定一个 FTP VCOUNT 参数,该参数可以设置数据集可以跨越的卷数(每个卷最多可以有 15 个扩展区)。这可以产生绝对庞大的数据集。

所有这些都表明,理解 IBM 大型机上的传统数据集分配涉及一些巫术。

依靠存储管理系统 (SMS) 为您计算,生活可以变得更简单。大多数商店都会有短信。不必进行所有数学计算来计算主要/次要范围大小,您可能只需要求适当的 SMS DATACLAS。大多数安装都会有一些适合大型数据集的东西,比如你的。每个安装都定义了自己的 DATACLS 名称,因此您的大型机人员将不得不为您挖掘它们。SMS DATACLAS 使用 FTP LOCSITE 选项指定:DATAC=xxx 其中 xxx 是适当的 DATACLAS 名称。

于 2012-03-01T16:37:21.683 回答