public BufferedInputStream getFileInputStream(String filePath) {
BufferedInputStream is = null;
try {
logger.debug("FtpUtils->getFileInputStream->FTP开始下载文件!");
FTPFile ftpFile = ftpClient.mlistFile(filePath);
if (null != ftpFile) {
is = new BufferedInputStream(ftpClient.retrieveFileStream(filePath));
} else {
throw new BaseException("FtpUtils->getFileInputStream->找不到文件!");
}
logger.debug("FtpUtils->getFileInputStream->FTP下载文件成功!");
} catch (Exception e) {
e.printStackTrace();
}
return is;
}
执行retrieveFileStream后执行FTPClient后面的操作如changeWorkingDirectory、listFiles会失败,在Debug时使用静态方法测试调用listFiles时出现以下错误,但程序正常运行时没有抛出异常,
java.io.IOException: Unable to determine system type - response: 451 Another command is currently pending, please try again later.
at org.apache.commons.net.ftp.FTPClient.getSystemType(FTPClient.java:2801)
at org.apache.commons.net.ftp.FTPClient.__createParser(FTPClient.java:3369)
at org.apache.commons.net.ftp.FTPClient.initiateListParsing(FTPClient.java:3338)
at org.apache.commons.net.ftp.FTPClient.listFiles(FTPClient.java:3016)
?
原因:读完InputStream后必须在关闭它,如果不这样做,不关闭后续命令可能会意外地执行。要完成文件传输,必须调用completePendingCommand completePendingCommand和检查其返回值以验证是否成功。如果不这样做,后续命令可能会意外地执行。retrieveFileStream注释如下:
/**
* Returns an InputStream from which a named file from the server
* can be read. If the current file type is ASCII, the returned
* InputStream will convert line separators in the file to
* the local representation. You must close the InputStream when you
* finish reading from it. The InputStream itself will take care of
* closing the parent data connection socket upon being closed.
* <p>
* <b>To finalize the file transfer you must call
* {@link #completePendingCommand completePendingCommand } and
* check its return value to verify success.</b>
* If this is not done, subsequent commands may behave unexpectedly.
* <p>
* Note: if you have used {@link #setRestartOffset(long)},
* the file data will start from the selected offset.
*
* @param remote The name of the remote file.
* @return An InputStream from which the remote file can be read. If
* the data connection cannot be opened (e.g., the file does not
* exist), null is returned (in which case you may check the reply
* code to determine the exact reason for failure).
* @throws FTPConnectionClosedException
* If the FTP server prematurely closes the connection as a result
* of the client being idle or some other reason causing the server
* to send FTP reply code 421. This exception may be caught either
* as an IOException or independently as itself.
* @throws IOException If an I/O error occurs while either sending a
* command to the server or receiving a reply from the server.
*/
public InputStream retrieveFileStream(String remote) throws IOException
{
return _retrieveFileStream(FTPCmd.RETR.getCommand(), remote);
}
/**
* There are a few FTPClient methods that do not complete the
* entire sequence of FTP commands to complete a transaction. These
* commands require some action by the programmer after the reception
* of a positive intermediate command. After the programmer's code
* completes its actions, it must call this method to receive
* the completion reply from the server and verify the success of the
* entire transaction.
* <p>
* For example,
* <pre>
* InputStream input;
* OutputStream output;
* input = new FileInputStream("foobaz.txt");
* output = ftp.storeFileStream("foobar.txt")
* if(!FTPReply.isPositiveIntermediate(ftp.getReplyCode())) {
* input.close();
* output.close();
* ftp.logout();
* ftp.disconnect();
* System.err.println("File transfer failed.");
* System.exit(1);
* }
* Util.copyStream(input, output);
* input.close();
* output.close();
* // Must call completePendingCommand() to finish command.
* if(!ftp.completePendingCommand()) {
* ftp.logout();
* ftp.disconnect();
* System.err.println("File transfer failed.");
* System.exit(1);
* }
* </pre>
*
* @return True if successfully completed, false if not.
* @throws FTPConnectionClosedException
* If the FTP server prematurely closes the connection as a result
* of the client being idle or some other reason causing the server
* to send FTP reply code 421. This exception may be caught either
* as an IOException or independently as itself.
* @throws IOException If an I/O error occurs while either sending a
* command to the server or receiving a reply from the server.
*/
public boolean completePendingCommand() throws IOException
{
return FTPReply.isPositiveCompletion(getReply());
}
解决方案:关闭流,调用completePendingCommand()方法
InputStream in = ftpClient.retrieveFileStream(fileName);
in.close();
ftpClient.completePendingCommand();
|