天天看點

FSDataOutputStream (淺析hadoop寫入資料api)

對于一般檔案,都有滿足随機讀寫的api。而hadoop中的讀api很簡單用FSDataInputStream類就可以滿足一般要求,而hadoop中的寫操作卻是和普通java操作不一樣。

Hadoop對于寫操作提供了一個類:FSDataOutputStream,這個類重載了很多write方法,用于寫入很多類型的資料:比如位元組數組,long,int,char等等。像FSDataInputStream一樣,要獲得FSDataOutputStream的執行個體,必須通過FileSystem該類來和HDFS建立連接配接,然後通過路徑傳回FSDataOutputStream執行個體。FileSystem傳回FSDataOutputStream執行個體的方法有兩組:

1、create(Path p)函數,建立一個空檔案,然後可以向該檔案順序寫入

2、append(Path p)函數,打開一個已有檔案,并最做檔案末尾追加資料

以上兩組函數都有多個重載版本,可以查閱手冊。FSDataOutputStream不允許在檔案中定位(而FSDataInputStream可以),這是因為hadoop隻允許在一個已打開檔案順序寫入或在檔案尾追加資料,不允許在結尾之外其他檔案寫入資料。

在使用append的操作時可能傳回異常dfs.support.append未設定為true,隻要才hdfs-site.xml中把該屬性設定為true

<property>  
  <name>dfs.support.append</name>  
  <value>false</value>  
  <description>Does HDFS allow appends to files?  
               This is currently set to false because there are bugs in the  
               "append code" and is not supported in any prodction cluster.  
  </description>  
</property>  
           

而且0.20的早起版本也不支援append操作,官方文檔的建議是如果追加資料就重新create一個檔案。使用的時候應該謹慎一點。

當讀取檔案時若要傳回檔案的大小,用下列代碼:

FileStatus status=hdfs.getFileStatus(p);  
            return status.getLen(); 
           

但是當對檔案寫入時,FileStatus的getLen函數傳回的不是目前的大小,因為FSDataInputStream在寫入資料時,資料會緩存,隻有當寫入的資料滿64M(塊大小)時或者關閉檔案時,才會把資料寫入到檔案中去。連續寫入資料時,為了實時擷取目前檔案大小,如果連續關閉打開檔案勢必會影響效率。可以這樣解決:

long result;  
if(outFsData!=null){//FSDataInputStream對象執行個體  
result=writeInitSize+outFsData.size()//檔案打開時的長度  
}  
else{  
FileStatus status=hdfs.getFileStatus(p);  
result=status.getLen();//這個getLen()傳回的是int型,最大也就是4G,要注意  
}  
return result; 
           

FSDataOutputStream該類的size函數就是傳回的緩沖區寫入的資料的大小。

參考:http://blog.csdn.net/qiuchenl/article/details/8617990