java ftp批量下载文件,偶尔出现空文件问题

 

■1.问题现象

ftp批量下载文件时,偶尔出现空文件。

■2.问题原因

A:代码环境

整体环境:springboot2.0.4

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.4.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

 ftp环境:org.apache.commons.net.ftp

        <dependency>
            <groupId>commons-net</groupId>
            <artifactId>commons-net</artifactId>
            <version>3.3</version>
        </dependency>
    /**
     * 下载指定目录下指定后缀名文件
     *
     * @param hostname  FTP服务器地址
     * @param port      FTP服务器端口号
     * @param username  FTP登录帐号
     * @param password  FTP登录密码
     * @param pathname  FTP服务器文件目录
     * @param localpath 下载后的文件路径
     * @return
     */
    public static List<String> downloadFileForSubfix(String hostname, int port, String username, String password, String pathname,
                                                     int spanId, String localpath, String[] subfixs, Integer connectId) {
        List<String> fileNames = new ArrayList<>();
        List<FTPFile> fTPFiles = new ArrayList<>();
        // org.apache.commons.net.ftp
        FTPClient ftp = null;
        try {
            ftp = getFTPClient(hostname, username, password, port);
            // 主动模式
            ftp.enterLocalActiveMode();
            // 设置文件类型  二进制文件
            ftp.setFileType(FTPClient.BINARY_FILE_TYPE);
            // 切换目录
            boolean flag = ftp.changeWorkingDirectory(new String(pathname.getBytes(), FTP.DEFAULT_CONTROL_ENCODING));
            if (!flag) {
                throw new Exception("目录[" + pathname + "]不存在");
            }
            FTPFile[] fs = ftp.listFiles(pathname, file -> {
                String name = file.getName();
                String strSubName = name.substring(name.lastIndexOf("."));
                for (String subfix : subfixs) {
                    if (subfix.equalsIgnoreCase(strSubName)) {
                        return true;
                    }
                }
                return false;
            });
            for (FTPFile ftpFile : fs) {
                if(ftpFile.isFile()){
                    fTPFiles.add(ftpFile);
                }
            }
            //文件排序--时间早的文件优先处理
            Collections.sort(fTPFiles, (file, newFile) -> {
                if (file.getTimestamp().getTimeInMillis() < newFile.getTimestamp().getTimeInMillis()) {
                    return -1;
                } else if (file.getTimestamp().getTimeInMillis() == newFile.getTimestamp().getTimeInMillis()) {
                    return 0;
                } else {
                    return 1;
                }
            });
            for (int i = 0; i < fTPFiles.size(); i++) {
                if (i >= DiConstants.FTP_FILE_COUNT_20s) {
                    break;
                }
                FTPFile ff = fTPFiles.get(i);
                String strNewName = writeFile(ff, localpath, ftp, connectId);
                //deleteFile(hostname, port, username, password, pathname, strNewName);
                fileNames.add(strNewName);
            }
        } catch (Exception e) {
            logger.error("FTP下载文件异常{}", e);
        } finally {
            try {
                if (ftp != null) {
                    ftp.logout();
                }
            } catch (IOException e1) {
                e1.printStackTrace();
            }

            if (ftp.isConnected()) {
                try {
                    ftp.disconnect();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return fileNames;
    }

    public static String writeFile(FTPFile ff, String localpath, FTPClient ftp, Integer connectId) {
        FileOutputStream out = null;
        InputStream in = null;
        String outFileName = ff.getName();
        String strConnect = "CONNECT";
        String strNewName = strConnect.concat(DiConstants.MARK_LEFT_BRACKET).concat(String.format("%03d", connectId))
                .concat(DiConstants.MARK_RIGHT_BRACKET).concat(outFileName);
        try {
            File localFile = new File(localpath.concat(File.separator).concat(strNewName));
            out = new FileOutputStream(localFile);
            //TODO 默认为ASCII文件编码格式但是需要改成二进制
            ftp.setFileType(FTP.BINARY_FILE_TYPE);
            in = ftp.retrieveFileStream(outFileName);
            byte[] byteArray = new byte[4096];
            int read = 0;
            while ((read = in.read(byteArray)) != -1) {
                out.write(byteArray, 0, read);
                out.flush();
            }
            // 要多次操作这个ftp的流的通道,要等他的每次命令完成
            ftp.completePendingCommand();   //TODO 这个有点问题
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //TODO 为什么要这么写????
            if (null != out) {
                try {
                    out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (null != in) {
                try {
                    in.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return strNewName;

    }

经测试发现[in = ftp.retrieveFileStream(outFileName);]中获取的in中未获取读出内容(猜测可能是读取文件偶尔会很慢,造成了阻塞),程序无法进入后面的whil循环,导致空文件。 

■3.解决办法

    /**
     * 下载指定目录下指定后缀名文件
     *
     * @param hostname  FTP服务器地址
     * @param port      FTP服务器端口号
     * @param username  FTP登录帐号
     * @param password  FTP登录密码
     * @param pathname  FTP服务器文件目录
     * @param localpath 下载后的文件路径
     * @return
     */
    public static List<String> downloadFileForSubfix(String hostname, int port, String username, String password, String pathname,
	            int spanId, String localpath, String[] subfixs, Integer connectId) {
		List<String> fileNames = new ArrayList<>();
		List<FTPFile> fTPFiles = new ArrayList<>();
		// org.apache.commons.net.ftp
		FTPClient ftp = null;
		try {
			ftp = getFTPClient(hostname, username, password, port);
			// 主动模式
			ftp.enterLocalActiveMode();
			// 设置文件类型  二进制文件
			ftp.setFileType(FTPClient.BINARY_FILE_TYPE);
			ftp.setBufferSize(1*1024*1024);
			// 切换目录
			boolean flag = ftp.changeWorkingDirectory(new String(pathname.getBytes(), FTP.DEFAULT_CONTROL_ENCODING));
			if (!flag) {
				throw new Exception("目录[" + pathname + "]不存在");
			}
			FTPFile[] fs = ftp.listFiles(pathname, file -> {
				String name = file.getName();
				String strSubName = name.substring(name.lastIndexOf("."));
				for (String subfix : subfixs) {
					if (subfix.equalsIgnoreCase(strSubName)) {
						return true;
					}
				}
				return false;
			});
			for (FTPFile ftpFile : fs) {
				if(ftpFile.isFile()){
                    fTPFiles.add(ftpFile);
                }
			}
			//文件排序--时间早的文件优先处理
			Collections.sort(fTPFiles, (file, newFile) -> {
				if (file.getTimestamp().getTimeInMillis() < newFile.getTimestamp().getTimeInMillis()) {
					return -1;
				} else if (file.getTimestamp().getTimeInMillis() == newFile.getTimestamp().getTimeInMillis()) {
					return 0;
				} else {
					return 1;
				}
			});
			for (int i = 0; i < fTPFiles.size(); i++) {
				if (i >= DiConstants.FTP_FILE_COUNT_20s) {
					break;
				}
				FTPFile ff = fTPFiles.get(i);
				String strNewName = writeFile(ff, localpath, ftp, connectId);
				//deleteFile(hostname, port, username, password, pathname, strNewName);
				// 空文件判断
				if(StringUtils.isEmpty(strNewName)){
					break;
				}
				fileNames.add(strNewName);
			}
		} catch (Exception e) {
			logger.error("FTP下载文件异常{}", e);
		} finally {
			try {
				if (ftp != null) {
					ftp.logout();
				}
			} catch (IOException e1) {
				e1.printStackTrace();
			}
		
			if (ftp.isConnected()) {
				try {
					ftp.disconnect();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		return fileNames;
	}
	
	public static String writeFile(FTPFile ff, String localpath, FTPClient ftp, Integer connectId) {
		FileOutputStream out = null;
		InputStream in = null;
		String outFileName = ff.getName();
		String strConnect = "CONNECT";
		String strNewName = "";
		try {
			in = ftp.retrieveFileStream(new String(outFileName.getBytes("GB2312"),"ISO-8859-1"));
			if(in.available() > 0){
				strNewName = strConnect.concat(DiConstants.MARK_LEFT_BRACKET).concat(String.format("%03d", connectId)).concat(DiConstants.MARK_RIGHT_BRACKET).concat(outFileName);
				File localFile = new File(localpath.concat(File.separator).concat(strNewName));
				out = new FileOutputStream(localFile);
				
				byte[] byteArray = new byte[4096];
				int read = 0;
				while ((read = in.read(byteArray)) != -1) {
					out.write(byteArray, 0, read);
					out.flush();
				}
				out.close();
			}
			in.close();
			// 要多次操作这个ftp的流的通道,要等他的每次命令完成
			ftp.completePendingCommand();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (null != out) {
				try {
					out.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			if (null != in) {
				try {
					in.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		return strNewName;
	}

 获取[in = ftp.retrieveFileStream(outFileName);]后判断再进行文件下载操作。如果不能读取文件内容,就停止本次操作。

 

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要使用Java实现FTP批量下载文件,可以使用Apache的Commons Net库来简化FTP操作。以下是一个使用Java实现的简单示例: 首先,需要在项目中导入Apache Commons Net库的依赖,例如使用Maven: ``` <dependency> <groupId>commons-net</groupId> <artifactId>commons-net</artifactId> <version>3.7.2</version> </dependency> ``` 然后,可以创建一个FTP下载器的类来实现批量下载文件的功能。示例代码如下: ```java import org.apache.commons.net.ftp.FTP; import org.apache.commons.net.ftp.FTPClient; import java.io.FileOutputStream; import java.io.IOException; public class FTPDownloader { private static final String SERVER = "ftp.example.com"; private static final int PORT = 21; private static final String USERNAME = "username"; private static final String PASSWORD = "password"; public static void main(String[] args) { FTPClient ftpClient = new FTPClient(); try { ftpClient.connect(SERVER, PORT); ftpClient.login(USERNAME, PASSWORD); ftpClient.setFileTransferMode(FTP.BINARY_FILE_TYPE); ftpClient.enterLocalPassiveMode(); ftpClient.setFileType(FTP.BINARY_FILE_TYPE); ftpClient.changeWorkingDirectory("/path/to/remote/directory"); String[] fileNames = ftpClient.listNames(); for (String fileName : fileNames) { if (fileName.endsWith(".txt")) { FileOutputStream outputStream = new FileOutputStream("download/" + fileName); ftpClient.retrieveFile(fileName, outputStream); outputStream.close(); } } ftpClient.logout(); ftpClient.disconnect(); } catch (IOException e) { e.printStackTrace(); } } } ``` 在上述代码中,我们首先创建了一个`FTPClient`对象,并连接到指定的FTP服务器。然后,我们使用登录凭据进行身份验证。 接下来,我们设置FTP客户端的传输模式和文件类型为二进制。我们还设置了被动模式,以避免由于防火墙等原因导致的连接问题。 然后,我们切换到FTP服务器上指定的远程目录,并获取该目录中的所有文件名列表。 最后,我们遍历文件名列表,检查文件扩展名,如果文件扩展名为`.txt`,则将其下载到本地目录`download/`中。 最后,我们断开与FTP服务器的连接。 请注意,上述代码仅提供一个简单的示例,并未处理所有可能出现的异常情况。在实际应用中,您可能需要进一步完善代码,以处理可能的错误和异常情况。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值