從ftp主機取xx數據檔.





千萬級別只是個概念,代表數據量等於千萬或者大於千萬的數據

 

本分享不牽扯分散式採集存儲之類的.是在一台機器上處理數據,如果數據量很大很大的話,可以考慮分散式處理,如果以後我有這方面的經驗,會及時分享的.





1、程式採用的ftp工具, apache 的 commons-net-ftp-2.0.jar




2、千萬級別ftp核心關鍵的部分--列目錄到檔,只要是這塊做好了,基本上性能就沒有太大的問題了.




可以通過apache 發送ftp命令 "NLST" 的方式列目錄到檔中去




# ftp列目錄執行的命令 以環境變量的配置優先,不配置則使用默認的列目錄方式 NLST
# DS_LIST_CMD = NLST
public File sendCommandAndListToFile(String command,String localPathName) throws IOException
{
try {
return client.createFile(command, localPathName);
} catch (IOException e) {
log.error(e);
throw new IOException("the command "+command +" is incorrect");
}
}



當然應該還有其他形式的,大家可以自己研究一下




十萬級別以上的數據量的話千萬不要使用下面這種方式,如果用的話 ==== 找死




FTPFile[] dirList = client.listFiles();

 

3、分批次從檔中讀取 要下載的檔案名. 加載到內存中處理,或者讀取一個檔案名就下載一個檔,不要把所有的數據都加載到內存,如果很多的話會出問題




為啥要分批次?

 

因為是大數據量,如果有1000W條記錄,列出來的目錄檔的大小 1G以上吧








4、檔下載的核心代碼----關於檔的斷點續傳, 獲得ftp檔的大小和本地檔的大小進行判斷,然後使用ftp提供的斷點續傳功能

 

下載檔一定要使用二進制的形式

 

client.enterLocalPassiveMode();// 設置為被動模式

 

ftpclient.binary(); // 一定要使用二進制模式



/** 下載所需的檔並支援斷點續傳,下載後刪除FTP檔,以免重複
* @param pathName 遠程檔
* @param localPath 本地檔
* @param registerFileName 記錄本檔案名稱目錄
* @param size 上傳檔案大小
* @return true 下載及刪除成功
* @throws IOException
* @throws Exception
*/
public boolean downLoad(String pathName, String localPath) throws IOException {
boolean flag = false;
File file = new File(localPath+".tmp");//設置臨時檔
FileOutputStream out = null;
try{
client.enterLocalPassiveMode();// 設置為被動模式
client.setFileType(FTP.BINARY_FILE_TYPE);//設置為二進制傳輸
if(lff.getIsFileExists(file)){//判斷本地檔是否存在,如果存在並且長度小於FTP檔的長度時斷點續傳;返之新增
long size = this.getSize(pathName);
long localFileSize = lff.getSize(file);
if(localFileSize > size){
return false;
}
out = new FileOutputStream(file,true);
client.setRestartOffset(localFileSize);
flag = client.retrieveFile(new String(pathName.getBytes(),client.getControlEncoding()),out);

 

out.flush();
} else{
out = new FileOutputStream(file);
flag = client.retrieveFile(new String(pathName.getBytes(),client.getControlEncoding()),out);

 

out.flush();
}

 

}catch(IOException e){
log.error(e);
log.error("file download error !");
throw e;
}finally{
try{
if(null!=out)
out.close();
if(flag)
lff.rename(file, localPath);
}catch(IOException e){
throw e;
}
}
return flag;
}
/**
* 獲取檔長度
* @param fileNamepath 本機檔
* @return
* @throws IOException
*/
public long getSize(String fileNamepath) throws IOException{
FTPFile [] ftp = client.listFiles(new String(fileNamepath.getBytes(),client.getControlEncoding()));
return ftp.length==0 ? 0 : ftp[0].getSize();
}

 

檢測本地檔是否已經下載,如果下載檔的大小.

 

/**
*本地檔的 獲取檔的大小
* @param file
* @return
*/
public long getSize(File file){
long size = 0;
if(getIsFileExists(file)){
size = file.length();
}
return size;
}






5、因為程式要跑最多100多個線程,在線程監控上做了一些處理,可以檢測那些死掉的線程,並及時的拉起來。

 

t.setUncaughtExceptionHandler(new ThreadException(exList));

 

原理:給每個線程添加 UncaughtExceptionHandler,死掉的時候把線程對應的資訊加入到一個list裏面,然後讓主線程每隔一段時間掃描一下list,如果有數據,直接重新建一個線程運行即可





6、如果程式是常駐內存的話,別忘記了在finally中關閉掉 不用的ftp連接





7、做大數據庫採集程式必須考慮到的一件事情 磁盤空間已滿的處理




java虛擬機對於磁盤空間已滿,在英文環境下的 linux aix 機器上 一般報

 

There is not enough space in the file system

 

中文環境下 一般報 "磁盤空間已滿"

 

大家可以使用下面的代碼進行驗證




//linux aix There is not enough space in the file system
// window There is not enough space in the file system
if(e.toString().contains("enough space")||e.toString().contains("磁盤空間已滿"))
{
log.error("channel "+channel_name + " There is not enough space on the disk ");
Runtime.getRuntime().exit(0);
}
 
創作者介紹
創作者 shadow 的頭像
shadow

資訊園

shadow 發表在 痞客邦 留言(0) 人氣()