帮同事查看ftp上传文件失败的问题,发现了以上报错。
排查文件路径是否有授权
查看了linux中的文件目录,查看是否为权限问题(如有问题,可执行:chmod -R 777 文件夹名)。
使用debug查看sendCommand方法返回的replycode为250,也表明文件夹创建成功。
查看是否是切换文件夹路径时报错
切换文件夹路径方法名为:changeWorkingDirectory。通过idea debug模式的evaluate查看ftp的当前路径:printWorkingDirectory,发现result为null!!!ftp是根据当前路径一层层去切换路径的,初始路径为null肯定会导致失败。
初始化ftp时,是给ftp初始化了路径的,为什么此时当前路径为null呢?后查看发现同事是先从ftp获取了文件(调用了方法:retrieveFileStream),然后再执行文件上传。在从ftp上传文件夹前,printWorkingDirectory打印的目录是有值的,执行完retrieveFileStream方法后,再调用printWorkingDirectory方法,返回结果就为null了。
解决方案
为什么会变成null,原因不清楚。现有解决方案是,执行retrieveFileStream方法并将流关闭后,要执行completePendingCommand方法,这时,printWorkingDirectory方法又能正常返回当前文件路径了。
public ByteArrayOutputStream downloadStream(String ftpPath, String fileName) throws IOException {
if (!setReady()) {
throw new RuntimeException("ftp 连接失败");
}
// 切换到文件目录下,并获取目录下所有文件
client.changeWorkingDirectory(ftpPath);
FTPFile[] ftpFiles = client.listFiles(ftpPath);
// 判断文件是否存在
Boolean have = false;
int size = 0;
for (FTPFile ftpFile : ftpFiles) {
if(StringUtil.equals(ftpFile.getName(),fileName)){
// 避免编码问题,将匹配的文件名称赋值给 fileName
fileName = ftpFile.getName();
size = (int) ftpFile.getSize();
have = true;
}
}
// 判断文件是否存在
if(!have){
throw new RuntimeException("未查找到该文件");
}
// 建立传输连接,并读取文件 InputStream
client.enterLocalPassiveMode();
InputStream in = client.retrieveFileStream(new String(fileName.getBytes(config.getLocalEncoding()), config.getRemoteEncoding()));
ByteArrayOutputStream out = new ByteArrayOutputStream();
byte[] b = new byte[(int) size];
int len = 0;
while ((len = in.read(b)) != -1) {
out.write(b, 0, len);
}
out.flush();
in.close();
client.completePendingCommand();
return out;
}