这是一个工作问题,我已经努力解决了大约一个星期,但没有成功。
我有使用 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% 确定这个问题是由大型机站点命令引起的。
如果您能提供任何帮助,我将不胜感激!!