今天發現用 如下方法下載一個2.2M的zip文件但是只下載了500K沒有下載完全,但是方法 返回的卻是true
FTPClientConfig conf = new FTPClientConfig(FTPClientConfig.SYST_UNIX);
ftp.configure(conf);
發現有時候成功有時候失敗(有時候只下載了1.8M就返回true了)
后來又設置了ftp.setDataTimeout(300 * 1000);
ftp.setReceiveBufferSize(1024 * 1024);
ftp.setBufferSize(1024 * 1024);
試了幾次沒有發現只下載了部分(比如1.8M)的問題了,后續再繼續觀察
20190919更新
部署到正式環境發現CKS的ftp下載還是有下載不完全問題,我又改了一下程序,判斷下載下來的文件大小和ftp上的文件大小是不是size相等,不相等就不刪除,等待下次重新下載。如果是zip文件還可以判斷一下是否是能夠解壓的zip再刪除。具體代碼如下
public static boolean downloadFile(String ftpOdmPath, Integer port, OdmInfo odmInfo, String downloadLocalPath){
boolean downloadStatus = false;
FTPClient ftp = new FTPClient();
ftp.setControlEncoding("UTF-8");
try {
int reply;
ftp.setDefaultTimeout(30 * 1000);
ftp.setConnectTimeout(30 * 1000);
ftp.setDataTimeout(300 * 1000);
FTPClientConfig conf = new FTPClientConfig(FTPClientConfig.SYST_UNIX);
ftp.configure(conf);
logger.info("start to connect ftp server");
ftp.connect(odmInfo.getFtpserver(), port);// 連接FTP服務器
logger.info("connect ftp server success");
ftp.login(odmInfo.getFtpusername(), odmInfo.getFtppwd());// 登錄
//設置ftp為被動模式,解決有時候ftp會卡住問題
ftp.enterLocalPassiveMode();
ftp.setReceiveBufferSize(1024 * 1024);
ftp.setBufferSize(1024 * 1024);
logger.info("login ftp server success");
reply = ftp.getReplyCode();
logger.info("reply======"+reply);
if (!FTPReply.isPositiveCompletion(reply)) {
ftp.disconnect();
return downloadStatus;
}
ftp.setFileType(FTPClient.BINARY_FILE_TYPE);
//切換FTP目錄
logger.info("ftpOdmPath======"+ftpOdmPath);
boolean changeDirStatus=ftp.changeWorkingDirectory(ftpOdmPath);
if(changeDirStatus)
{
FTPFile[] ftpFiles = ftp.listFiles();
for(FTPFile file : ftpFiles){
long fileSize=file.getSize();
OutputStream os=null;
boolean retrieveStatus=false;
try {
logger.info("download file======"+downloadLocalPath + "/" + file.getName());
File localFile = new File(downloadLocalPath + "/" + file.getName());
if (!localFile.getParentFile().exists()) {
localFile.getParentFile().mkdirs();
}
if(localFile.isDirectory())
{
continue;
}
os = new FileOutputStream(localFile);
retrieveStatus=ftp.retrieveFile(file.getName(), os);
logger.info("ftp download file======"+file.getName()+"===="+retrieveStatus);
if(os!=null)
{
os.flush();
}
} catch (Exception e) {
// TODO Auto-generated catch block
logger.error("",e);
} finally {
if(os!=null)
{
os.close();
}
}
//如果下載成功刪除ftp上的文件,並且文件大小和ftp上的一樣才刪除文件,如果是zip文件還要判斷一下是不是zip文件再刪除ftp上的文件
if(retrieveStatus)
{
try {
File localFileCheckSize = new File(downloadLocalPath + "/" + file.getName());
long localFileSize=localFileCheckSize.length();
logger.info("ftp file size======"+fileSize+"===local file size===="+localFileSize);
if(fileSize==localFileSize)
{
if(file.getName()!=null&&file.getName().endsWith(".zip"))
{
if(CompressUtil.checkZipFile(localFileCheckSize))
{
ftp.dele(file.getName());
logger.info("delete ftp file======"+file.getName());
}
else
{
logger.info("download from ftp file is not zip file======"+downloadLocalPath + "/" + file.getName());
}
}
else
{
ftp.dele(file.getName());
logger.info("delete ftp file======"+file.getName());
}
}
} catch (Exception e) {
// TODO Auto-generated catch block
logger.error("",e);
}
}
}
}
ftp.logout();
downloadStatus = true;
logger.info("download file success");
} catch (Exception e) {
logger.error("",e);
downloadStatus = false;
} finally{
if(ftp.isConnected()){
try{
ftp.disconnect();
}catch(IOException e){
logger.error("",e);
downloadStatus = false;
}
}
}
return downloadStatus;
}
如下網上的文章是解決這次問題的參考
https://blog.csdn.net/dise0092/article/details/100765177
在使用java的ftp下載服務器上的文件獲取文件的byte[],然后對byte進行加密傳輸時,
注意是要獲取byte[],而不是下載文件到本地;
發現下載的byte[]大小總是小於文件實際大小,並且下載的大小是變化的
到網上查閱發現,ftp傳輸是不穩定的,會隨網絡情況波動;
所以對下載的方法進行了修改;
import sun.net.ftp.FtpClient;
import sun.net.ftp.FtpProtocolException;
public String download(String ftpFile, FtpClient ftpClient) {
InputStream is = null;
byte[] data = null;
try {
// 獲取ftp上的文件
long size=ftpClient.getSize(ftpFile);
System.out.println(ftpClient.getSize(ftpFile));
is = ftpClient.getFileStream(ftpFile);
// System.out.println(is.available());
int count =is.available();
System.out.println("count:"+count);
while (count>0 || (data==null?0:data.length)<size) {// 獲取到的大小小於文件大小也進入
byte[] b = new byte[count];
is.read(b);
System.out.println("b:"+b.length);
data= byteMerger(b,data);
count = is.available();
}
is.close();
ftpClient.close();
}catch (FtpProtocolException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
// 加密
System.out.println("data size:"+data.length);
String encodeBase64Str =org.apache.commons.codec.binary.Base64.encodeBase64String(data);
return encodeBase64Str;
}
// 參考 https://blog.csdn.net/shb2058/article/details/52637213
public static byte[] byteMerger(byte[] byte1, byte[] byte2){
if (byte1==null && byte2!=null){
return byte2;
}
if (byte2 == null && byte1!=null){
return byte1;
}
if (byte2 == null && byte1 ==null){
return null;
}
byte[] byte3 = new byte[byte1.length+byte2.length];
System.arraycopy(byte1, 0, byte3, 0, byte1.length);
System.arraycopy(byte2, 0, byte3, byte1.length, byte2.length);
return byte3;
}
/***
* 連接ftp
* @param url
* @param port
* @param username
* @param password
* @return
*/
public FtpClient connectFTP(String url, int port, String username, String password) {
//創建ftp
FtpClient ftp = null;
try {
//創建地址
SocketAddress addr = new InetSocketAddress(url, port);
//連接
ftp = FtpClient.create();
ftp.connect(addr);
//登陸
ftp.login(username, password.toCharArray());
ftp.setBinaryType();
ftp.enablePassiveMode(true);//這句最好加告訴對面服務器開一個端口
} catch (FtpProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return ftp;
}
運行發現果然波動是很大的
參考:
https://blog.csdn.net/shb2058/article/details/52637213
網上還有個說法,下午試試
如果小文件可以下載,但是大文件下載后缺少幾字節之類的話,可以設置ftpClient.setFileType(FTP.BINARY_FILE_TYPE)以二進制去傳輸,如果是大文件直接完全下載不了,卡死的話,建議設置為ftpClient.enterLocalPassiveMode(),並且設置超時時間,做一個5-10次的for循環,保證能夠下載下來。
